diff --git a/workspaces/leetcode-api/schema-patched.graphql b/workspaces/leetcode-api/schema-patched.graphql index 1343c512..ef4f844f 100644 --- a/workspaces/leetcode-api/schema-patched.graphql +++ b/workspaces/leetcode-api/schema-patched.graphql @@ -10419,7 +10419,7 @@ type QuestionNode { stats: JSONString! status: String submitUrl: String! - title: String! + title: String! @trim titleSlug: String! @slug topicTags: [TopicTagNode!]! translatedContent: String @@ -11008,7 +11008,7 @@ type SubmissionDumpNode { statusDisplay: String time: String timestamp: String! - title: String! + title: String! @trim titleSlug: String! @slug topicTags: [TopicTagNode] url: String @@ -12217,4 +12217,6 @@ directive @nonnegative on FIELD_DEFINITION directive @slug on FIELD_DEFINITION +directive @trim on FIELD_DEFINITION + directive @enum(values: [String!]!) on FIELD_DEFINITION diff --git a/workspaces/leetcode-api/src/api/active-daily-coding-challenge-question/fetchGraphQL.generated.ts b/workspaces/leetcode-api/src/api/active-daily-coding-challenge-question/fetchGraphQL.generated.ts index 9aa1ef96..5525864c 100644 --- a/workspaces/leetcode-api/src/api/active-daily-coding-challenge-question/fetchGraphQL.generated.ts +++ b/workspaces/leetcode-api/src/api/active-daily-coding-challenge-question/fetchGraphQL.generated.ts @@ -33,7 +33,7 @@ export const queryResultZodType = z.object({ question: z.object({ difficulty: z.enum(["Easy", "Medium", "Hard"]), questionFrontendId: z.string(), - title: z.string(), + title: z.string().trim(), titleSlug: slugZodType, }), }), diff --git a/workspaces/leetcode-api/src/api/question-list/fetchGraphQL.generated.ts b/workspaces/leetcode-api/src/api/question-list/fetchGraphQL.generated.ts index 52f3c460..fc8d9730 100644 --- a/workspaces/leetcode-api/src/api/question-list/fetchGraphQL.generated.ts +++ b/workspaces/leetcode-api/src/api/question-list/fetchGraphQL.generated.ts @@ -48,7 +48,7 @@ export const queryResultZodType = z.object({ difficulty: z.enum(["Easy", "Medium", "Hard"]), isPaidOnly: z.boolean(), questionFrontendId: z.string(), - title: z.string(), + title: z.string().trim(), titleSlug: slugZodType, }), ), diff --git a/workspaces/leetcode-api/src/api/recent-ac-submission-list/fetchGraphQL.generated.ts b/workspaces/leetcode-api/src/api/recent-ac-submission-list/fetchGraphQL.generated.ts index 4b9aa705..8b3c8c78 100644 --- a/workspaces/leetcode-api/src/api/recent-ac-submission-list/fetchGraphQL.generated.ts +++ b/workspaces/leetcode-api/src/api/recent-ac-submission-list/fetchGraphQL.generated.ts @@ -28,7 +28,7 @@ export const queryResultZodType = z.object({ recentAcSubmissionList: z.array( z.object({ id: z.string(), - title: z.string(), + title: z.string().trim(), titleSlug: slugZodType, timestamp: z.string(), }), diff --git a/workspaces/leetcode-api/src/scripts/codegen/graphqlToZod.ts b/workspaces/leetcode-api/src/scripts/codegen/graphqlToZod.ts index d0bb43e0..adbb7e88 100644 --- a/workspaces/leetcode-api/src/scripts/codegen/graphqlToZod.ts +++ b/workspaces/leetcode-api/src/scripts/codegen/graphqlToZod.ts @@ -18,6 +18,7 @@ import { type DirectivesConfig = { nonnegative?: boolean; slug?: boolean; + trim?: boolean; enumValues?: string[]; }; @@ -49,6 +50,11 @@ function parseDirectives( res.slug = true; break; } + case "trim": { + invariant(!directive.arguments?.length, "No arguments allowed!"); + res.trim = true; + break; + } default: { throw new Error("Unsupported directive " + directive.name.value); } @@ -91,10 +97,7 @@ function generateZod( } case "Int": { const { nonnegative, ...rest } = parseDirectives(directives); - invariant( - Object.values(rest).every((v) => v === false), - "Unsupported directives!", - ); + invariant(Object.keys(rest).length === 0, "Unsupported directives!"); return [ new ZodOutput( @@ -120,14 +123,11 @@ function generateZod( return [new ZodOutput("z.string()", true), []]; } case "String": { - const { slug, enumValues, ...rest } = parseDirectives(directives); - invariant(!(slug && enumValues), "Incompatible directive combination!"); - invariant( - Object.values(rest).every((v) => v === false), - "Unsupported directives!", - ); + const { slug, trim, enumValues, ...rest } = parseDirectives(directives); + invariant(Object.keys(rest).length === 0, "Unsupported directives!"); if (enumValues) { + invariant(!slug && !trim, "Incompatible directive combination!"); return [ new ZodOutput(`z.enum(${JSON.stringify(enumValues)})`, true), [], @@ -135,13 +135,17 @@ function generateZod( } if (slug) { + invariant(!trim, "@trim is redundant when @slug is enabled!"); return [ new ZodOutput("slugZodType", true), ['import { slugZodType } from "../../zod-types/slugZodType.ts"'], ]; } - return [new ZodOutput("z.string()", true), []]; + return [ + new ZodOutput(["z.string()", trim ? ".trim()" : ""].join(""), true), + [], + ]; } default: { throw new Error("Unsupported scalar type: " + currentType.name); diff --git a/workspaces/leetcode-api/src/scripts/patch-graphql-schema/addDirectiveToField.ts b/workspaces/leetcode-api/src/scripts/patch-graphql-schema/addDirectiveToField.ts index 119a1ff2..71c16b9d 100644 --- a/workspaces/leetcode-api/src/scripts/patch-graphql-schema/addDirectiveToField.ts +++ b/workspaces/leetcode-api/src/scripts/patch-graphql-schema/addDirectiveToField.ts @@ -9,7 +9,7 @@ import { nameNode } from "./astNodeBuilders.ts"; // TODO: keep in sync with DirectivesConfig in graphqlToZod -export const CUSTOM_DIRECTIVES = ["nonnegative", "slug"] as const; +export const CUSTOM_DIRECTIVES = ["nonnegative", "slug", "trim"] as const; // TODO: memoize by directiveName? diff --git a/workspaces/leetcode-api/src/scripts/patch-graphql-schema/modifications.ts b/workspaces/leetcode-api/src/scripts/patch-graphql-schema/modifications.ts index 3d24cf14..83acdc0a 100644 --- a/workspaces/leetcode-api/src/scripts/patch-graphql-schema/modifications.ts +++ b/workspaces/leetcode-api/src/scripts/patch-graphql-schema/modifications.ts @@ -68,6 +68,7 @@ export const FIELD_MODIFICATIONS: SafeObjectMap< solutionNum: [markNonNull, addDirective("nonnegative")], stats: [markNonNull], submitUrl: [markNonNull], + title: [addDirective("trim")], titleSlug: [addDirective("slug")], topicTags: [markNonNull], urlManager: [markNonNull], @@ -75,7 +76,7 @@ export const FIELD_MODIFICATIONS: SafeObjectMap< SubmissionDumpNode: { id: [markNonNull], timestamp: [markNonNull], - title: [markNonNull], + title: [markNonNull, addDirective("trim")], titleSlug: [markNonNull, addDirective("slug")], }, };