Skip to content

Commit 48c5df6

Browse files
authored
Adds better error messages for unparsable babel files: (#2175)
1 parent d3b1540 commit 48c5df6

File tree

5 files changed

+53
-6
lines changed

5 files changed

+53
-6
lines changed

.changeset/ten-pianos-report.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"graphql-language-service-server": patch
3+
"graphql-language-service": patch
4+
---
5+
6+
Better handling of unparsable babel JS/TS files

packages/graphql-language-service-server/src/MessageProcessor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class MessageProcessor {
127127
this._graphQLConfig = config;
128128
this._parser = (text, uri) => {
129129
const p = parser ?? parseDocument;
130-
return p(text, uri, fileExtensions, graphqlFileExtensions);
130+
return p(text, uri, fileExtensions, graphqlFileExtensions, this._logger);
131131
};
132132
this._tmpDir = tmpDir || tmpdir();
133133
this._tmpDirBase = path.join(this._tmpDir, 'graphql-language-service');

packages/graphql-language-service-server/src/__tests__/MessageProcessor-test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,26 @@ export function Example(arg: string) {}`;
623623
expect(contents.length).toEqual(0);
624624
});
625625

626+
it('an unparsable JS/TS file does not throw and bring down the server', async () => {
627+
const text = `
628+
// @flow
629+
import type randomthing fro 'package';
630+
import type {B} from 'B';
631+
im port A from './A';
632+
633+
con QUERY = randomthing\`
634+
query Test {
635+
test {
636+
value
637+
...FragmentsComment
638+
}
639+
}
640+
\${A.frag`;
641+
642+
const contents = parseDocument(text, 'test.js');
643+
expect(contents.length).toEqual(0);
644+
});
645+
626646
describe('handleWatchedFilesChangedNotification', () => {
627647
const mockReadFileSync: jest.Mock = jest.requireMock('fs').readFileSync;
628648

packages/graphql-language-service-server/src/findGraphQLTags.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import { Position, Range } from 'graphql-language-service-utils';
1818

1919
import { parse, ParserOptions, ParserPlugin } from '@babel/parser';
20+
import { Logger } from './Logger';
2021

2122
// Attempt to be as inclusive as possible of source text.
2223
const PARSER_OPTIONS: ParserOptions = {
@@ -68,18 +69,36 @@ const BABEL_PLUGINS: ParserPlugin[] = [
6869
'logicalAssignment',
6970
];
7071

71-
export function findGraphQLTags(text: string, ext: string): TagResult[] {
72+
export function findGraphQLTags(
73+
text: string,
74+
ext: string,
75+
uri: string,
76+
logger: Logger,
77+
): TagResult[] {
7278
const result: TagResult[] = [];
7379

7480
const plugins = BABEL_PLUGINS.slice(0, BABEL_PLUGINS.length);
7581

76-
if (ext === '.ts' || ext === '.tsx') {
82+
const isTypeScript = ext === '.ts' || ext === '.tsx';
83+
if (isTypeScript) {
7784
plugins?.push('typescript');
7885
} else {
7986
plugins?.push('flow', 'flowComments');
8087
}
8188
PARSER_OPTIONS.plugins = plugins;
82-
const ast = parse(text, PARSER_OPTIONS);
89+
90+
let parsedAST: ReturnType<typeof parse> | undefined = undefined;
91+
try {
92+
parsedAST = parse(text, PARSER_OPTIONS);
93+
} catch (error) {
94+
const type = isTypeScript ? 'TypeScript' : 'JavaScript';
95+
logger.error(
96+
`Could not parse the ${type} file at ${uri} to extract the graphql tags:`,
97+
);
98+
logger.error(error);
99+
return [];
100+
}
101+
const ast = parsedAST!;
83102

84103
const visitors = {
85104
CallExpression: (node: Expression) => {

packages/graphql-language-service-server/src/parseDocument.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { CachedContent } from 'graphql-language-service';
33
import { Range, Position } from 'graphql-language-service-utils';
44

55
import { findGraphQLTags, DEFAULT_TAGS } from './findGraphQLTags';
6+
import { Logger } from './Logger';
67

78
export const DEFAULT_SUPPORTED_EXTENSIONS = [
89
'.js',
@@ -17,7 +18,7 @@ export const DEFAULT_SUPPORTED_EXTENSIONS = [
1718
];
1819

1920
/**
20-
* .graphql is the officially reccomended extension for graphql files
21+
* .graphql is the officially recommended extension for graphql files
2122
*
2223
* .gql and .graphqls are included for compatibility for commonly used extensions
2324
*
@@ -43,6 +44,7 @@ export function parseDocument(
4344
uri: string,
4445
fileExtensions: string[] = DEFAULT_SUPPORTED_EXTENSIONS,
4546
graphQLFileExtensions: string[] = DEFAULT_SUPPORTED_GRAPHQL_EXTENSIONS,
47+
logger: Logger = new Logger(),
4648
): CachedContent[] {
4749
// Check if the text content includes a GraphQLV query.
4850
// If the text doesn't include GraphQL queries, do not proceed.
@@ -51,7 +53,7 @@ export function parseDocument(
5153
if (DEFAULT_TAGS.some(t => t === text)) {
5254
return [];
5355
}
54-
const templates = findGraphQLTags(text, ext);
56+
const templates = findGraphQLTags(text, ext, uri, logger);
5557
return templates.map(({ template, range }) => ({ query: template, range }));
5658
}
5759
if (graphQLFileExtensions.some(e => e === ext)) {

0 commit comments

Comments
 (0)