Skip to content

Commit e45ba17

Browse files
authored
Create a lint diagnostic from invalid schema (#3463)
* Create a lint diagnostic from invalid schema * Create two-doors-shave.md * add config option to show error on invalid schema
1 parent 57c2d7f commit e45ba17

File tree

4 files changed

+75
-39
lines changed

4 files changed

+75
-39
lines changed

.changeset/two-doors-shave.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"cm6-graphql": patch
3+
---
4+
5+
Create a lint diagnostic from invalid schema

packages/cm6-graphql/src/interfaces.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GraphQLSchema } from 'graphql';
44
import { ContextToken, CompletionItem } from 'graphql-language-service';
55
import { Position } from './helpers';
66
export interface GqlExtensionsOptions {
7+
showErrorOnInvalidSchema?: boolean;
78
onShowInDocs?: (field?: string, type?: string, parentType?: string) => void;
89
onFillAllFields?: (
910
view: EditorView,

packages/cm6-graphql/src/lint.ts

Lines changed: 61 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,78 @@
11
import { Diagnostic, linter } from '@codemirror/lint';
22
import { getDiagnostics } from 'graphql-language-service';
33
import { Position, posToOffset } from './helpers';
4-
import { getSchema, optionsStateField, schemaStateField } from './state';
4+
import {
5+
getOpts,
6+
getSchema,
7+
optionsStateField,
8+
schemaStateField,
9+
} from './state';
510
import { Extension } from '@codemirror/state';
11+
import { validateSchema } from 'graphql';
612

713
const SEVERITY = ['error', 'warning', 'info'] as const;
814

915
export const lint: Extension = linter(
1016
view => {
11-
try {
12-
const schema = getSchema(view.state);
13-
if (!schema) {
17+
const schema = getSchema(view.state);
18+
const options = getOpts(view.state);
19+
if (!schema) {
20+
return [];
21+
}
22+
const validationErrors = validateSchema(schema);
23+
if (validationErrors.length) {
24+
if (!options?.showErrorOnInvalidSchema) {
1425
return [];
1526
}
16-
const results = getDiagnostics(view.state.doc.toString(), schema);
1727

18-
return results
19-
.map((item): Diagnostic | null => {
20-
if (!item.severity || !item.source) {
21-
return null;
22-
}
28+
const combinedError = validationErrors.map(error => {
29+
return error.message;
30+
});
2331

24-
const calculatedFrom = posToOffset(
25-
view.state.doc,
26-
new Position(item.range.start.line, item.range.start.character),
27-
);
28-
const from = Math.max(
29-
0,
30-
Math.min(calculatedFrom, view.state.doc.length),
31-
);
32-
const calculatedRo = posToOffset(
33-
view.state.doc,
34-
new Position(item.range.end.line, item.range.end.character - 1),
35-
);
36-
const to = Math.min(
37-
Math.max(from + 1, calculatedRo),
38-
view.state.doc.length,
39-
);
40-
return {
41-
from,
42-
to: from === to ? to + 1 : to,
43-
severity: SEVERITY[item.severity - 1],
44-
// source: item.source, // TODO:
45-
message: item.message,
46-
actions: [], // TODO:
47-
};
48-
})
49-
.filter((_): _ is Diagnostic => Boolean(_));
50-
} catch {
51-
return [];
32+
return [
33+
{
34+
from: 0,
35+
to: view.state.doc.length,
36+
severity: 'error',
37+
message: combinedError.join('\n'),
38+
actions: [], // TODO:
39+
},
40+
];
5241
}
42+
const results = getDiagnostics(view.state.doc.toString(), schema);
43+
44+
return results
45+
.map((item): Diagnostic | null => {
46+
if (!item.severity || !item.source) {
47+
return null;
48+
}
49+
50+
const calculatedFrom = posToOffset(
51+
view.state.doc,
52+
new Position(item.range.start.line, item.range.start.character),
53+
);
54+
const from = Math.max(
55+
0,
56+
Math.min(calculatedFrom, view.state.doc.length),
57+
);
58+
const calculatedRo = posToOffset(
59+
view.state.doc,
60+
new Position(item.range.end.line, item.range.end.character - 1),
61+
);
62+
const to = Math.min(
63+
Math.max(from + 1, calculatedRo),
64+
view.state.doc.length,
65+
);
66+
return {
67+
from,
68+
to: from === to ? to + 1 : to,
69+
severity: SEVERITY[item.severity - 1],
70+
// source: item.source, // TODO:
71+
message: item.message,
72+
actions: [], // TODO:
73+
};
74+
})
75+
.filter((_): _ is Diagnostic => Boolean(_));
5376
},
5477
{
5578
needsRefresh(vu) {

packages/cm6-graphql/src/state.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,14 @@ export const getOpts = (state: EditorState) => {
4949
return state.field(optionsStateField);
5050
};
5151

52+
const defaultOpts: GqlExtensionsOptions = {
53+
showErrorOnInvalidSchema: true,
54+
};
55+
5256
export const stateExtensions = (
5357
schema?: GraphQLSchema,
5458
opts?: GqlExtensionsOptions,
55-
) => [schemaStateField.init(() => schema), optionsStateField.init(() => opts)];
59+
) => [
60+
schemaStateField.init(() => schema),
61+
optionsStateField.init(() => ({ ...defaultOpts, ...opts })),
62+
];

0 commit comments

Comments
 (0)