Skip to content

Commit 9180b54

Browse files
authored
Merge pull request #12714 from quarto-dev/feature/zod
Feature/zod
2 parents e750702 + aee23ea commit 9180b54

24 files changed

+2815
-512
lines changed

deno.jsonc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
// auto-generated by package/src/common/create-deno-config.ts
22
// see dev-docs/update-deno_jsonc.md
33
{
4+
"compilerOptions": {
5+
"noErrorTruncation": true
6+
},
47
"lint": {
58
"include": ["src/"],
69
"exclude": [

package/src/common/create-schema-types.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ import {
1414
generateJsonSchemasFromSchemas,
1515
} from "../../../src/core/schema/json-schema-from-schema.ts";
1616

17+
import {
18+
generateZodTypesFromSchemas,
19+
} from "../../../src/core/schema/zod-types-from-schema.ts";
20+
1721
await generateTypesFromSchemas(Deno.args[0]);
1822
await generateSchemaTypes(Deno.args[0]);
19-
await generateJsonSchemasFromSchemas(Deno.args[0]);
23+
await generateJsonSchemasFromSchemas(Deno.args[0]);
24+
await generateZodTypesFromSchemas(Deno.args[0]);

src/command/render/pandoc.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -197,11 +197,7 @@ import {
197197
MarkdownPipelineHandler,
198198
} from "../../core/markdown-pipeline.ts";
199199
import { getenv } from "../../core/env.ts";
200-
import {
201-
BrandFontBunny,
202-
BrandFontFile,
203-
BrandFontGoogle,
204-
} from "../../resources/types/schema-types.ts";
200+
import { Zod } from "../../resources/types/zod/schema-types.ts";
205201
import { kFieldCategories } from "../../project/types/website/listing/website-listing-shared.ts";
206202
import { isWindows } from "../../deno_ral/platform.ts";
207203
import { appendToCombinedLuaProfile } from "../../core/performance/perfetto-utils.ts";
@@ -1480,19 +1476,19 @@ async function resolveExtras(
14801476
// deno-lint-ignore no-explicit-any
14811477
const source: string = (_font as any).source ?? "google";
14821478
if (source === "file") {
1483-
const font = _font as BrandFontFile;
1479+
const font = Zod.BrandFontFile.parse(_font);
14841480
for (const file of font.files || []) {
14851481
const path = typeof file === "object" ? file.path : file;
14861482
fontdirs.add(dirname(join(brand.brandDir, path)));
14871483
}
14881484
} else if (source === "bunny") {
1489-
const font = _font as BrandFontBunny;
1485+
const font = Zod.BrandFontBunny.parse(_font);
14901486
console.log(
14911487
"Font bunny is not yet supported for Typst, skipping",
14921488
font.family,
14931489
);
14941490
} else if (source === "google" /* || font.source === "bunny" */) {
1495-
const font = _font as BrandFontGoogle;
1491+
const font = Zod.BrandFontGoogle.parse(_font);
14961492
let { family, style, weight } = font;
14971493
const parts = [family!];
14981494
if (style) {

src/command/render/project.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ import { Format } from "../../config/types.ts";
8080
import { fileExecutionEngine } from "../../execute/engine.ts";
8181
import { projectContextForDirectory } from "../../project/project-context.ts";
8282
import { ProjectType } from "../../project/types/types.ts";
83-
import { ProjectConfig as ProjectConfig_Project } from "../../resources/types/schema-types.ts";
83+
import { Zod } from "../../resources/types/zod/schema-types.ts";
8484

8585
const noMutationValidations = (
8686
projType: ProjectType,
@@ -255,9 +255,11 @@ const mergeExtensionMetadata = async (
255255
context.isSingleFile ? undefined : context.dir,
256256
{ builtIn: false },
257257
);
258-
const projectMetadata = extensions.map((extension) =>
258+
const projectMetadata = extensions.filter((extension) =>
259259
extension.contributes.metadata?.project
260-
).filter((project) => project) as ProjectConfig_Project[];
260+
).map((extension) => {
261+
return Zod.ProjectConfig.parse(extension.contributes.metadata!.project);
262+
});
261263
context.config.project = mergeProjectMetadata(
262264
context.config.project,
263265
...projectMetadata,

src/core/brand/brand.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
BrandTypography,
1515
BrandTypographyOptionsBase,
1616
BrandTypographyOptionsHeadings,
17-
} from "../../resources/types/schema-types.ts";
17+
Zod,
18+
} from "../../resources/types/zod/schema-types.ts";
1819
import { InternalError } from "../lib/error.ts";
1920

2021
import { join, relative } from "../../deno_ral/path.ts";
@@ -67,11 +68,15 @@ export class Brand {
6768
projectDir: string;
6869
processedData: ProcessedBrandData;
6970

70-
constructor(readonly brand: BrandJson, brandDir: string, projectDir: string) {
71-
this.data = brand;
71+
constructor(
72+
readonly brand: unknown,
73+
brandDir: string,
74+
projectDir: string,
75+
) {
76+
this.data = Zod.Brand.parse(brand);
7277
this.brandDir = brandDir;
7378
this.projectDir = projectDir;
74-
this.processedData = this.processData(brand);
79+
this.processedData = this.processData(this.data);
7580
}
7681

7782
processData(data: BrandJson): ProcessedBrandData {
@@ -261,8 +266,10 @@ export class Brand {
261266
if (typeof entry === "string") {
262267
return { path: join(pathPrefix, entry) };
263268
}
264-
entry.path = join(pathPrefix, entry.path);
265-
return entry;
269+
return {
270+
...entry,
271+
path: join(pathPrefix, entry.path),
272+
};
266273
}
267274

268275
getLogo(name: "small" | "medium" | "large"): CanonicalLogoInfo | undefined {

src/core/sass/brand.ts

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ import {
1616
import { ProjectContext } from "../../project/types.ts";
1717
import {
1818
BrandFont,
19-
BrandFontBunny,
19+
// BrandFontBunny,
2020
BrandFontCommon,
2121
BrandFontGoogle,
2222
BrandFontWeight,
23-
} from "../../resources/types/schema-types.ts";
23+
Zod,
24+
} from "../../resources/types/zod/schema-types.ts";
2425
import { Brand } from "../brand/brand.ts";
2526
import { darkModeDefault } from "../../format/html/format-html-info.ts";
2627

@@ -323,10 +324,11 @@ const brandTypographyLayer = (
323324
): string | undefined => {
324325
let googleFamily = "";
325326
for (const _resolvedFont of font) {
326-
const resolvedFont = _resolvedFont as (BrandFontGoogle | BrandFontBunny);
327-
if (resolvedFont.source !== "google") {
327+
const safeResolvedFont = Zod.BrandFontGoogle.safeParse(_resolvedFont);
328+
if (!safeResolvedFont.success) {
328329
return undefined;
329330
}
331+
const resolvedFont = safeResolvedFont.data;
330332
const thisFamily = resolvedFont.family;
331333
if (!thisFamily) {
332334
continue;
@@ -351,17 +353,15 @@ const brandTypographyLayer = (
351353
): string | undefined => {
352354
let googleFamily = "";
353355
for (const _resolvedFont of font) {
354-
const resolvedFont =
355-
_resolvedFont as (BrandFont | BrandFontGoogle | BrandFontBunny);
356+
const safeResolvedFont = Zod.BrandFontBunny.safeParse(_resolvedFont);
357+
if (!safeResolvedFont.success) {
358+
return undefined;
359+
}
360+
const resolvedFont = safeResolvedFont.data;
356361
// Typescript's type checker doesn't understand that it's ok to attempt
357362
// to access a property that might not exist on a type when you're
358363
// only testing for its existence.
359364

360-
// deno-lint-ignore no-explicit-any
361-
const source = (resolvedFont as any).source;
362-
if (source && source !== "bunny") {
363-
return undefined;
364-
}
365365
const thisFamily = resolvedFont.family;
366366
if (!thisFamily) {
367367
continue;
@@ -384,6 +384,7 @@ const brandTypographyLayer = (
384384
type HTMLFontInformation = { [key: string]: unknown };
385385

386386
type FontKind =
387+
| "link"
387388
| "base"
388389
| "headings"
389390
| "monospace"
@@ -398,9 +399,14 @@ const brandTypographyLayer = (
398399
} else if (typeof resolvedFontOptions === "string") {
399400
resolvedFontOptions = { family: resolvedFontOptions };
400401
}
401-
const family = resolvedFontOptions.family;
402-
const font = getFontFamilies(family);
403402
const result: HTMLFontInformation = {};
403+
// This is an ugly hack:
404+
// resolvedFontOptions doesn't always have 'family', but at this
405+
// point in the code we know resolvedFontOptions is an object
406+
// that we can attempt to extract the family from.
407+
const family =
408+
(resolvedFontOptions as Record<string, string | undefined>).family;
409+
const font = getFontFamilies(family);
404410
result.family = resolveGoogleFontFamily(font) ??
405411
resolveBunnyFontFamily(font) ??
406412
// resolveFilesFontFamily(font) ??
@@ -524,11 +530,9 @@ const brandTypographyLayer = (
524530
"monospace",
525531
"headings",
526532
"base",
527-
]
533+
] as const
528534
) {
529-
const fontInformation = resolveHTMLFontInformation(
530-
kind as FontKind,
531-
);
535+
const fontInformation = resolveHTMLFontInformation(kind);
532536
if (!fontInformation) {
533537
continue;
534538
}

src/core/schema/build-schema-file.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { kLangCommentChars } from "../lib/partition-cell-options.ts";
3737
import { generateTypesFromSchemas } from "./types-from-schema.ts";
3838
import { generateJsonSchemasFromSchemas } from "./json-schema-from-schema.ts";
3939
import { InternalError } from "../lib/error.ts";
40+
import { generateZodTypesFromSchemas } from "./zod-types-from-schema.ts";
4041

4142
////////////////////////////////////////////////////////////////////////////////
4243

@@ -90,6 +91,7 @@ export async function buildIntelligenceResources() {
9091
await Promise.all([
9192
generateTypesFromSchemas(path),
9293
generateJsonSchemasFromSchemas(path),
94+
generateZodTypesFromSchemas(path),
9395
]);
9496
}
9597

src/core/schema/types-from-schema.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ export function typeNameFromSchemaName(schemaName: string) {
2626
return capitalize(toCapitalizationCase(schemaName.replaceAll("/", "-")));
2727
}
2828

29-
function fmtSource(source: string) {
29+
export function fmtSource(source: string) {
3030
return new Deno.Command(Deno.execPath(), {
3131
args: ["fmt", source],
3232
}).output();
3333
}
3434

3535
export const generatedSrcMessage =
36-
`// This file is automatically generated by \`quarto build-js\`! Do not edit.",
36+
`// This file is automatically generated by \`quarto dev-call build-artifacts\`! Do not edit.",
3737
//
38-
// If you find yourself trying to rebuild types and \`quarto build-js\` won't run because
38+
// If you find yourself trying to rebuild types and \`quarto dev-call build-artifacts\` won't run because
3939
// of bad type definitions, run the following:
4040
// $ cd $QUARTO_ROOT
4141
// $ ./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) {
104104
await fmtSource(join(resourcePath, "/types/schema-types.ts"));
105105
}
106106

107-
function yamlToTypeScriptKey(key: string) {
107+
export function yamlToTypeScriptKey(key: string) {
108108
// if the key isn't a valid typescript identifier, quote it
109109
if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(key)) {
110110
return JSON.stringify(key);

0 commit comments

Comments
 (0)