Skip to content

Commit be5a7b7

Browse files
committed
chore: rebase against main, and fix conflicts
2 parents 0409284 + a388300 commit be5a7b7

File tree

11 files changed

+609
-545
lines changed

11 files changed

+609
-545
lines changed

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "graphql-codegen-typescript-validation-schema",
33
"version": "0.15.0",
4-
"packageManager": "pnpm@9.3.0",
4+
"packageManager": "pnpm@9.4.0",
55
"description": "GraphQL Code Generator plugin to generate form validation schema from your GraphQL schema",
66
"respository": {
77
"type": "git",
@@ -76,14 +76,14 @@
7676
"@tsconfig/recommended": "1.0.6",
7777
"@types/graphlib": "^2.1.8",
7878
"@types/node": "^20.0.0",
79-
"eslint": "9.4.0",
79+
"eslint": "9.5.0",
8080
"jest": "29.7.0",
8181
"myzod": "1.11.0",
8282
"npm-run-all2": "6.2.0",
8383
"ts-dedent": "^2.2.0",
84-
"ts-jest": "29.1.4",
84+
"ts-jest": "29.1.5",
8585
"typescript": "5.4.5",
86-
"valibot": "0.31.1",
86+
"valibot": "0.33.3",
8787
"vitest": "^1.0.0",
8888
"yup": "1.4.0",
8989
"zod": "3.23.8"

pnpm-lock.yaml

Lines changed: 509 additions & 535 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig {
230230
/**
231231
* @description Uses the full path of the enum type as the default value instead of the stringified value.
232232
* @default { enumValues: "change-case-all#pascalCase" }
233+
* @link https://the-guild.dev/graphql/codegen/docs/config-reference/naming-convention
233234
*
234235
* @exampleMarkdown
235236
* ```yml

src/graphql.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,20 @@ export function isGeneratedByIntrospection(schema: GraphQLSchema): boolean {
185185
.filter(([name, type]) => !name.startsWith('__') && !isSpecifiedScalarType(type))
186186
.every(([, type]) => type.astNode === undefined)
187187
}
188+
189+
// https://spec.graphql.org/October2021/#EscapedCharacter
190+
const escapeMap: { [key: string]: string } = {
191+
'\"': '\\\"',
192+
'\\': '\\\\',
193+
'\/': '\\/',
194+
'\b': '\\b',
195+
'\f': '\\f',
196+
'\n': '\\n',
197+
'\r': '\\r',
198+
'\t': '\\t',
199+
};
200+
201+
export function escapeGraphQLCharacters(input: string): string {
202+
// eslint-disable-next-line regexp/no-escape-backspace
203+
return input.replace(/["\\/\f\n\r\t\b]/g, match => escapeMap[match]);
204+
}

src/myzod/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type { Visitor } from '../visitor';
2323
import {
2424
InterfaceTypeDefinitionBuilder,
2525
ObjectTypeDefinitionBuilder,
26+
escapeGraphQLCharacters,
2627
isInput,
2728
isListType,
2829
isNamedType,
@@ -292,7 +293,7 @@ function generateFieldTypeMyZodSchema(config: ValidationSchemaPluginConfig, visi
292293
appliedDirectivesGen = `${appliedDirectivesGen}.default(${visitor.convertName(type.name.value)}.${value})`;
293294
}
294295
else {
295-
appliedDirectivesGen = `${appliedDirectivesGen}.default("${defaultValue.value}")`;
296+
appliedDirectivesGen = `${appliedDirectivesGen}.default("${escapeGraphQLCharacters(defaultValue.value)}")`;
296297
}
297298
}
298299
}

src/yup/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type { Visitor } from '../visitor';
2323
import {
2424
InterfaceTypeDefinitionBuilder,
2525
ObjectTypeDefinitionBuilder,
26+
escapeGraphQLCharacters,
2627
isInput,
2728
isListType,
2829
isNamedType,
@@ -280,8 +281,9 @@ function shapeFields(fields: readonly (FieldDefinitionNode | InputValueDefinitio
280281
defaultValue?.kind === Kind.INT
281282
|| defaultValue?.kind === Kind.FLOAT
282283
|| defaultValue?.kind === Kind.BOOLEAN
283-
)
284+
) {
284285
fieldSchema = `${fieldSchema}.default(${defaultValue.value})`;
286+
}
285287

286288
if (defaultValue?.kind === Kind.STRING || defaultValue?.kind === Kind.ENUM) {
287289
if (config.useEnumTypeAsDefaultValue && defaultValue?.kind !== Kind.STRING) {
@@ -293,7 +295,7 @@ function shapeFields(fields: readonly (FieldDefinitionNode | InputValueDefinitio
293295
fieldSchema = `${fieldSchema}.default(${visitor.convertName(field.name.value)}.${value})`;
294296
}
295297
else {
296-
fieldSchema = `${fieldSchema}.default("${defaultValue.value}")`;
298+
fieldSchema = `${fieldSchema}.default("${escapeGraphQLCharacters(defaultValue.value)}")`;
297299
}
298300
}
299301
}

src/zod/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import type { Visitor } from '../visitor';
2323
import {
2424
InterfaceTypeDefinitionBuilder,
2525
ObjectTypeDefinitionBuilder,
26+
escapeGraphQLCharacters,
2627
isInput,
2728
isListType,
2829
isNamedType,
@@ -305,7 +306,7 @@ function generateFieldTypeZodSchema(config: ValidationSchemaPluginConfig, visito
305306
appliedDirectivesGen = `${appliedDirectivesGen}.default(${type.name.value}.${value})`;
306307
}
307308
else {
308-
appliedDirectivesGen = `${appliedDirectivesGen}.default("${defaultValue.value}")`;
309+
appliedDirectivesGen = `${appliedDirectivesGen}.default("${escapeGraphQLCharacters(defaultValue.value)}")`;
309310
}
310311
}
311312
}

tests/graphql.spec.ts

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
} from 'graphql';
1313
import dedent from 'ts-dedent';
1414

15-
import { ObjectTypeDefinitionBuilder, isGeneratedByIntrospection, topologicalSortAST, topsort } from '../src/graphql';
15+
import { ObjectTypeDefinitionBuilder, escapeGraphQLCharacters, isGeneratedByIntrospection, topologicalSortAST, topsort } from '../src/graphql';
1616

1717
describe('graphql', () => {
1818
describe('objectTypeDefinitionBuilder', () => {
@@ -297,3 +297,65 @@ describe('isGeneratedByIntrospection function', () => {
297297
expect(isGeneratedByIntrospection(clientSchema)).toBe(true);
298298
});
299299
});
300+
301+
describe('escapeGraphQLCharacters', () => {
302+
it('should escape double quotes', () => {
303+
const input = 'This is a "test" string.';
304+
const expected = 'This is a \\\"test\\\" string.';
305+
expect(escapeGraphQLCharacters(input)).toBe(expected);
306+
});
307+
308+
it('should escape backslashes', () => {
309+
const input = 'This is a backslash: \\';
310+
const expected = 'This is a backslash: \\\\';
311+
expect(escapeGraphQLCharacters(input)).toBe(expected);
312+
});
313+
314+
it('should escape forward slashes', () => {
315+
const input = 'This is a forward slash: /';
316+
const expected = 'This is a forward slash: \\/';
317+
expect(escapeGraphQLCharacters(input)).toBe(expected);
318+
});
319+
320+
it('should escape backspaces', () => {
321+
const input = 'This is a backspace: \b';
322+
const expected = 'This is a backspace: \\b';
323+
expect(escapeGraphQLCharacters(input)).toBe(expected);
324+
});
325+
326+
it('should escape form feeds', () => {
327+
const input = 'This is a form feed: \f';
328+
const expected = 'This is a form feed: \\f';
329+
expect(escapeGraphQLCharacters(input)).toBe(expected);
330+
});
331+
332+
it('should escape new lines', () => {
333+
const input = 'This is a new line: \n';
334+
const expected = 'This is a new line: \\n';
335+
expect(escapeGraphQLCharacters(input)).toBe(expected);
336+
});
337+
338+
it('should escape carriage returns', () => {
339+
const input = 'This is a carriage return: \r';
340+
const expected = 'This is a carriage return: \\r';
341+
expect(escapeGraphQLCharacters(input)).toBe(expected);
342+
});
343+
344+
it('should escape horizontal tabs', () => {
345+
const input = 'This is a tab: \t';
346+
const expected = 'This is a tab: \\t';
347+
expect(escapeGraphQLCharacters(input)).toBe(expected);
348+
});
349+
350+
it('should escape multiple special characters', () => {
351+
const input = 'This is a "test" string with \n new line and \t tab.';
352+
const expected = 'This is a \\\"test\\\" string with \\n new line and \\t tab.';
353+
expect(escapeGraphQLCharacters(input)).toBe(expected);
354+
});
355+
356+
it('should not escape non-special characters', () => {
357+
const input = 'Normal string with no special characters.';
358+
const expected = 'Normal string with no special characters.';
359+
expect(escapeGraphQLCharacters(input)).toBe(expected);
360+
});
361+
});

tests/myzod.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,7 @@ describe('myzod', () => {
13761376
input PageInput {
13771377
pageType: PageType! = PUBLIC
13781378
greeting: String = "Hello"
1379+
newline: String = "Hello\\nWorld"
13791380
score: Int = 100
13801381
ratio: Float = 0.5
13811382
isMember: Boolean = true
@@ -1399,6 +1400,7 @@ describe('myzod', () => {
13991400
return myzod.object({
14001401
pageType: PageTypeSchema.default("PUBLIC"),
14011402
greeting: myzod.string().default("Hello").optional().nullable(),
1403+
newline: myzod.string().default("Hello\\nWorld").optional().nullable(),
14021404
score: myzod.number().default(100).optional().nullable(),
14031405
ratio: myzod.number().default(0.5).optional().nullable(),
14041406
isMember: myzod.boolean().default(true).optional().nullable()

tests/yup.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1400,6 +1400,7 @@ describe('yup', () => {
14001400
input PageInput {
14011401
pageType: PageType! = PUBLIC
14021402
greeting: String = "Hello"
1403+
newline: String = "Hello\\nWorld"
14031404
score: Int = 100
14041405
ratio: Float = 0.5
14051406
isMember: Boolean = true
@@ -1423,6 +1424,7 @@ describe('yup', () => {
14231424
return yup.object({
14241425
pageType: PageTypeSchema.nonNullable().default("PUBLIC"),
14251426
greeting: yup.string().defined().nullable().default("Hello").optional(),
1427+
newline: yup.string().defined().nullable().default("Hello\\nWorld").optional(),
14261428
score: yup.number().defined().nullable().default(100).optional(),
14271429
ratio: yup.number().defined().nullable().default(0.5).optional(),
14281430
isMember: yup.boolean().defined().nullable().default(true).optional()

tests/zod.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ describe('zod', () => {
530530
`)
531531
});
532532

533-
it('with default input values as enum types', async () => {
533+
it('with default input values as enum types', async () => {
534534
const schema = buildSchema(/* GraphQL */ `
535535
enum PageType {
536536
PUBLIC
@@ -575,6 +575,7 @@ describe('zod', () => {
575575
input PageInput {
576576
pageType: PageType! = PUBLIC
577577
greeting: String = "Hello"
578+
newline: String = "Hello\\nWorld"
578579
score: Int = 100
579580
ratio: Float = 0.5
580581
isMember: Boolean = true
@@ -598,6 +599,7 @@ describe('zod', () => {
598599
return z.object({
599600
pageType: PageTypeSchema.default("PUBLIC"),
600601
greeting: z.string().default("Hello").nullish(),
602+
newline: z.string().default("Hello\\nWorld").nullish(),
601603
score: z.number().default(100).nullish(),
602604
ratio: z.number().default(0.5).nullish(),
603605
isMember: z.boolean().default(true).nullish()

0 commit comments

Comments
 (0)