Skip to content

Commit 975f29e

Browse files
cshaveracao
andauthored
fix: improve setSchema & schema loading, allow primitive schema (#1648)
- allow null schema - `api.setSchema()` works on it's own, and static string is evaluated as a schema - `api.setSchema()` now allows `string | GraphQLSchema` Co-authored-by: Rikki <[email protected]>
1 parent 2de91ba commit 975f29e

File tree

8 files changed

+216
-65
lines changed

8 files changed

+216
-65
lines changed

examples/monaco-graphql-webpack/src/index.ts

Lines changed: 113 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,74 @@ window.MonacoEnvironment = {
2828
},
2929
};
3030

31+
const schemas = {
32+
remote: {
33+
op: `
34+
query Example($limit: Int) {
35+
launchesPast(limit: $limit) {
36+
mission_name
37+
# format me using the right click context menu
38+
launch_date_local
39+
launch_site {
40+
site_name_long
41+
}
42+
links {
43+
article_link
44+
video_link
45+
}
46+
}
47+
}
48+
`,
49+
variables: `{ "limit": 10 }`,
50+
load: ({ op, variables }: { op: string; variables: string }) => {
51+
GraphQLAPI.setSchemaConfig({ uri: SCHEMA_URL });
52+
variablesEditor.setValue(variables);
53+
operationEditor.setValue(op);
54+
},
55+
},
56+
local: {
57+
op: `query Example {
58+
allTodos {
59+
id
60+
name
61+
}
62+
}`,
63+
load: ({ op }: { op: string }) => {
64+
setRawSchema();
65+
variablesEditor.setValue('{}');
66+
operationEditor.setValue(op);
67+
},
68+
},
69+
};
70+
71+
const THEME = 'vs-dark';
72+
3173
const schemaInput = document.createElement('input');
3274
schemaInput.type = 'text';
3375

3476
schemaInput.value = SCHEMA_URL;
3577

78+
const selectEl = document.createElement('select');
79+
80+
selectEl.onchange = e => {
81+
e.preventDefault();
82+
const type = selectEl.value as 'local' | 'remote';
83+
if (schemas[type]) {
84+
// @ts-ignore
85+
schemas[type].load(schemas[type]);
86+
}
87+
};
88+
89+
const createOption = (label: string, value: string) => {
90+
const el = document.createElement('option');
91+
el.label = label;
92+
el.value = value;
93+
return el;
94+
};
95+
96+
selectEl.appendChild(createOption('Remote', 'remote'));
97+
selectEl.appendChild(createOption('Local', 'local'));
98+
3699
schemaInput.onkeyup = e => {
37100
e.preventDefault();
38101
// @ts-ignore
@@ -44,6 +107,41 @@ schemaInput.onkeyup = e => {
44107

45108
const toolbar = document.getElementById('toolbar');
46109
toolbar?.appendChild(schemaInput);
110+
toolbar?.appendChild(selectEl);
111+
112+
async function setRawSchema() {
113+
await GraphQLAPI.setSchema(`# Enumeration type for a level of priority
114+
enum Priority {
115+
LOW
116+
MEDIUM
117+
HIGH
118+
}
119+
120+
# Our main todo type
121+
type Todo {
122+
id: ID!
123+
name: String!
124+
description: String
125+
priority: Priority!
126+
}
127+
128+
type Query {
129+
# Get one todo item
130+
todo(id: ID!): Todo
131+
# Get all todo items
132+
allTodos: [Todo!]!
133+
}
134+
135+
type Mutation {
136+
addTodo(name: String!, priority: Priority = LOW): Todo!
137+
removeTodo(id: ID!): Todo!
138+
}
139+
140+
schema {
141+
query: Query
142+
mutation: Mutation
143+
}`);
144+
}
47145

48146
const variablesModel = monaco.editor.createModel(
49147
`{}`,
@@ -56,6 +154,7 @@ const resultsEditor = monaco.editor.create(
56154
{
57155
model: variablesModel,
58156
automaticLayout: true,
157+
theme: THEME,
59158
},
60159
);
61160
const variablesEditor = monaco.editor.create(
@@ -64,11 +163,12 @@ const variablesEditor = monaco.editor.create(
64163
value: `{ "limit": 10 }`,
65164
language: 'json',
66165
automaticLayout: true,
166+
theme: THEME,
67167
},
68168
);
69169
const model = monaco.editor.createModel(
70170
`
71-
query Example($limit: Int) {
171+
query Example($limit: Int) {
72172
launchesPast(limit: $limit) {
73173
mission_name
74174
# format me using the right click context menu
@@ -95,6 +195,7 @@ const operationEditor = monaco.editor.create(
95195
formatOnPaste: true,
96196
formatOnType: true,
97197
folding: true,
198+
theme: THEME,
98199
},
99200
);
100201

@@ -104,8 +205,6 @@ GraphQLAPI.setFormattingOptions({
104205
},
105206
});
106207

107-
GraphQLAPI.setSchemaConfig({ uri: SCHEMA_URL });
108-
109208
/**
110209
* Basic Operation Exec Example
111210
*/
@@ -148,6 +247,17 @@ operationEditor.addAction(opAction);
148247
variablesEditor.addAction(opAction);
149248
resultsEditor.addAction(opAction);
150249

250+
/**
251+
* load local schema by default
252+
*/
253+
254+
let initialSchema = false;
255+
256+
if (!initialSchema) {
257+
schemas.remote.load(schemas.remote);
258+
initialSchema = true;
259+
}
260+
151261
// add your own diagnostics? why not!
152262
// monaco.editor.setModelMarkers(
153263
// model,
@@ -161,7 +271,3 @@ resultsEditor.addAction(opAction);
161271
// endColumn: 0,
162272
// }],
163273
// );
164-
165-
// operationEditor.onDidChangeModelContent(() => {
166-
// // this is where
167-
// })

packages/graphql-language-service/src/LanguageService.ts

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ import {
1212
getHoverInformation,
1313
} from 'graphql-language-service-interface';
1414

15-
import { RawSchema } from './types';
16-
1715
import {
1816
defaultSchemaLoader,
1917
SchemaConfig,
@@ -25,7 +23,7 @@ export type GraphQLLanguageConfig = {
2523
parser?: typeof parse;
2624
schemaLoader?: typeof defaultSchemaLoader;
2725
schemaBuilder?: typeof defaultSchemaBuilder;
28-
rawSchema?: RawSchema;
26+
schemaString?: string;
2927
parseOptions?: ParseOptions;
3028
schemaConfig: SchemaConfig;
3129
};
@@ -37,16 +35,16 @@ export class LanguageService {
3735
private _schemaResponse: SchemaResponse | null = null;
3836
private _schemaLoader: (
3937
schemaConfig: SchemaConfig,
40-
) => Promise<SchemaResponse | void> = defaultSchemaLoader;
38+
) => Promise<SchemaResponse | null> = defaultSchemaLoader;
4139
private _schemaBuilder = defaultSchemaBuilder;
42-
private _rawSchema: RawSchema | null = null;
40+
private _schemaString: string | null = null;
4341
private _parseOptions: ParseOptions | undefined = undefined;
4442
constructor({
4543
parser,
4644
schemaLoader,
4745
schemaBuilder,
4846
schemaConfig,
49-
rawSchema,
47+
schemaString,
5048
parseOptions,
5149
}: GraphQLLanguageConfig) {
5250
this._schemaConfig = schemaConfig;
@@ -59,8 +57,8 @@ export class LanguageService {
5957
if (schemaBuilder) {
6058
this._schemaBuilder = schemaBuilder;
6159
}
62-
if (rawSchema) {
63-
this._rawSchema = rawSchema;
60+
if (schemaString) {
61+
this._schemaString = schemaString;
6462
}
6563
if (parseOptions) {
6664
this._parseOptions = parseOptions;
@@ -80,28 +78,28 @@ export class LanguageService {
8078

8179
/**
8280
* setSchema statically, ignoring URI
83-
* @param schema {RawSchema}
81+
* @param schema {schemaString}
8482
*/
85-
public async setSchema(schema: RawSchema): Promise<GraphQLSchema> {
86-
this._rawSchema = schema;
87-
return this.loadSchema();
83+
public async setSchema(schema: string): Promise<void> {
84+
this._schemaString = schema;
85+
await this.loadSchema();
8886
}
8987

90-
public async getSchemaResponse(): Promise<SchemaResponse> {
88+
public async getSchemaResponse(): Promise<SchemaResponse | null> {
9189
if (this._schemaResponse) {
9290
return this._schemaResponse;
9391
}
9492
return this.loadSchemaResponse();
9593
}
9694

97-
public async loadSchemaResponse(): Promise<SchemaResponse> {
98-
if (this._rawSchema) {
99-
return typeof this._rawSchema === 'string'
100-
? this.parse(this._rawSchema)
101-
: this._rawSchema;
95+
public async loadSchemaResponse(): Promise<SchemaResponse | null> {
96+
if (this._schemaString) {
97+
return typeof this._schemaString === 'string'
98+
? this.parse(this._schemaString)
99+
: this._schemaString;
102100
}
103101
if (!this._schemaConfig?.uri) {
104-
throw new Error('uri missing');
102+
return null;
105103
}
106104
this._schemaResponse = (await this._schemaLoader(
107105
this._schemaConfig,
@@ -111,11 +109,15 @@ export class LanguageService {
111109

112110
public async loadSchema() {
113111
const schemaResponse = await this.loadSchemaResponse();
114-
this._schema = this._schemaBuilder(
115-
schemaResponse,
116-
this._schemaConfig.buildSchemaOptions,
117-
) as GraphQLSchema;
118-
return this._schema;
112+
if (schemaResponse) {
113+
this._schema = this._schemaBuilder(
114+
schemaResponse,
115+
this._schemaConfig.buildSchemaOptions,
116+
) as GraphQLSchema;
117+
return this._schema;
118+
} else {
119+
return null;
120+
}
119121
}
120122

121123
public async parse(text: string, options?: ParseOptions) {
@@ -126,23 +128,34 @@ export class LanguageService {
126128
_uri: string,
127129
documentText: string,
128130
position: Position,
129-
) =>
130-
getAutocompleteSuggestions(await this.getSchema(), documentText, position);
131+
) => {
132+
const schema = await this.getSchema();
133+
if (!schema) {
134+
return [];
135+
}
136+
return getAutocompleteSuggestions(schema, documentText, position);
137+
};
131138

132139
public getDiagnostics = async (
133140
_uri: string,
134141
documentText: string,
135142
customRules?: ValidationRule[],
136143
) => {
137-
if (!documentText || documentText.length < 1) {
144+
const schema = await this.getSchema();
145+
if (!documentText || documentText.length < 1 || !schema) {
138146
return [];
139147
}
140-
return getDiagnostics(documentText, await this.getSchema(), customRules);
148+
return getDiagnostics(documentText, schema, customRules);
141149
};
142150

143151
public getHover = async (
144152
_uri: string,
145153
documentText: string,
146154
position: Position,
147-
) => getHoverInformation(await this.getSchema(), documentText, position);
155+
) =>
156+
getHoverInformation(
157+
(await this.getSchema()) as GraphQLSchema,
158+
documentText,
159+
position,
160+
);
148161
}

packages/graphql-language-service/src/schemaLoader.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,25 @@ import {
99
} from 'graphql';
1010

1111
export type SchemaConfig = {
12-
uri: string;
12+
uri?: string;
1313
requestOpts?: RequestInit;
1414
introspectionOptions?: IntrospectionOptions;
1515
buildSchemaOptions?: BuildSchemaOptions;
1616
};
1717

1818
export type SchemaResponse = IntrospectionQuery | DocumentNode;
1919

20-
export type SchemaLoader = (config: SchemaConfig) => Promise<SchemaResponse>;
20+
export type SchemaLoader = (
21+
config: SchemaConfig,
22+
) => Promise<SchemaResponse | null>;
2123

2224
export const defaultSchemaLoader: SchemaLoader = async (
2325
schemaConfig: SchemaConfig,
24-
): Promise<SchemaResponse> => {
26+
): Promise<SchemaResponse | null> => {
2527
const { requestOpts, uri, introspectionOptions } = schemaConfig;
28+
if (!uri) {
29+
return null;
30+
}
2631
const fetchResult = await fetch(uri, {
2732
method: requestOpts?.method ?? 'post',
2833
body: JSON.stringify({

packages/monaco-graphql/src/GraphQLWorker.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import type { worker, editor, Position, IRange } from 'monaco-editor';
1212
import { getRange, LanguageService } from 'graphql-language-service';
1313

1414
import type {
15-
RawSchema,
1615
SchemaResponse,
1716
CompletionItem as GraphQLCompletionItem,
1817
} from 'graphql-language-service';
@@ -37,20 +36,19 @@ export class GraphQLWorker {
3736
private _formattingOptions: FormattingOptions | undefined;
3837
constructor(ctx: worker.IWorkerContext, createData: ICreateData) {
3938
this._ctx = ctx;
40-
// if you must, we have a nice default schema loader at home
4139
this._languageService = new LanguageService(createData.languageConfig);
4240
this._formattingOptions = createData.formattingOptions;
4341
}
4442

45-
async getSchemaResponse(_uri?: string): Promise<SchemaResponse> {
43+
async getSchemaResponse(_uri?: string): Promise<SchemaResponse | null> {
4644
return this._languageService.getSchemaResponse();
4745
}
4846

49-
async setSchema(schema: RawSchema): Promise<void> {
47+
async setSchema(schema: string): Promise<void> {
5048
await this._languageService.setSchema(schema);
5149
}
5250

53-
async loadSchema(_uri?: string): Promise<GraphQLSchema> {
51+
async loadSchema(_uri?: string): Promise<GraphQLSchema | null> {
5452
return this._languageService.getSchema();
5553
}
5654

0 commit comments

Comments
 (0)