Skip to content

Commit 1e02935

Browse files
committed
fix(load): handle parse errors correctly when it gets a string
1 parent a9dbd3b commit 1e02935

File tree

4 files changed

+58
-2
lines changed

4 files changed

+58
-2
lines changed

.changeset/late-hairs-joke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-tools/utils': patch
3+
---
4+
5+
Handle parse errors correctly when loader gets a string directly

packages/load/tests/loaders/schema/schema-from-string.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '../../../../testing/to-be-similar-string';
22
import '../../../../testing/to-be-similar-gql-doc';
33
import { printSchema } from 'graphql';
4+
import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader';
45
import { loadSchema, loadSchemaSync } from '@graphql-tools/load';
56
import { printSchemaWithDirectives } from '@graphql-tools/utils';
67
import { runTests, useMonorepo } from '../../../../testing/utils.js';
@@ -76,5 +77,25 @@ describe('schema from string', () => {
7677
}
7778
`);
7879
});
80+
it('should throw parse error', async () => {
81+
const schemaString = `
82+
extend type Query {
83+
test(id: String!): Test
84+
@resolveTo(
85+
sourceName: "Test"
86+
sourceTypeName: "Test"
87+
sourceFieldName: "test"
88+
requiredSelectionSet: "{ ...on Test { id name } }",
89+
sourceArgs: { testId: {root.id} }
90+
returnType: Test
91+
)
92+
}
93+
`;
94+
await expect(
95+
load(schemaString, {
96+
loaders: [new GraphQLFileLoader()],
97+
}),
98+
).rejects.toThrowError('Syntax Error');
99+
});
79100
});
80101
});

packages/utils/src/helpers.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { ASTNode, parse } from 'graphql';
22

3+
function isURL(str: string): boolean {
4+
try {
5+
const url = new URL(str);
6+
return !!url;
7+
} catch (e) {
8+
return false;
9+
}
10+
}
11+
312
export const asArray = <T>(fns: T | T[]) => (Array.isArray(fns) ? fns : fns ? [fns] : []);
413

514
const invalidDocRegex = /\.[a-z0-9]+$/i;
@@ -13,14 +22,22 @@ export function isDocumentString(str: any): boolean {
1322
// this why checking the extension is fast enough
1423
// and prevent from parsing the string in order to find out
1524
// if the string is a SDL
16-
if (invalidDocRegex.test(str)) {
25+
if (invalidDocRegex.test(str) || isURL(str)) {
1726
return false;
1827
}
1928

2029
try {
2130
parse(str);
2231
return true;
23-
} catch (e: any) {}
32+
} catch (e: any) {
33+
if (
34+
!e.message.includes('EOF') &&
35+
str.replace(/(\#[^*]*)/g, '').trim() !== '' &&
36+
str.includes(' ')
37+
) {
38+
throw new Error(`Failed to parse the GraphQL document. ${e.message}\n${str}`);
39+
}
40+
}
2441

2542
return false;
2643
}

packages/utils/tests/helpers.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,19 @@ describe('helpers', () => {
77
mutation: Mutation
88
subscription: Subscription
99
}`,
10+
/* GraphQL*/ `
11+
extend type Query {
12+
test(id: String!): Test
13+
@resolveTo(
14+
sourceName: "Test"
15+
sourceTypeName: "Test"
16+
sourceFieldName: "test"
17+
requiredSelectionSet: "{ ...on Test { id name } }",
18+
sourceArgs: { testId: {root.id} }
19+
returnType: Test
20+
)
21+
}
22+
`,
1023
])('should detect "%s" as NOT a valid path', str => {
1124
expect(isValidPath(str)).toBeFalsy();
1225
});

0 commit comments

Comments
 (0)