@mo36924/graphql-plugin 1.4.42 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.mjs CHANGED
@@ -6,367 +6,292 @@ import { getTokenAtPosition, getHoverInformation, getAutocompleteSuggestions, ge
6
6
  import { Position } from 'graphql-language-service-utils';
7
7
  import { CompletionItemKind, DiagnosticSeverity } from 'vscode-languageserver-types';
8
8
 
9
- const init = ({
10
- typescript: ts
11
- }) => {
12
- return {
13
- create(info) {
14
- const languageService = info.languageService;
15
- const config = info.config;
16
- const cwd = info.project.getCurrentDirectory();
17
- const modelPath = config.model && resolve(cwd, config.model);
18
- const schemaPath = config.schema && resolve(cwd, config.schema);
19
- const watchPath = modelPath || schemaPath;
20
- let schema = buildSchema("scalar Unknown");
21
-
22
- const addScalarUnknownType = schemaCode => schemaCode.includes("scalar Unknown") ? schemaCode : `${schemaCode}\nscalar Unknown`;
23
-
24
- const changeModel = () => {
25
- schema = buildSchema(addScalarUnknownType(printSchemaModel(readFileSync(modelPath, "utf8"))));
26
- };
27
-
28
- const changeSchema = () => {
29
- schema = buildSchema(addScalarUnknownType(readFileSync(schemaPath, "utf8")));
30
- };
31
-
32
- const update = modelPath ? changeModel : changeSchema;
33
-
34
- const listener = () => {
35
- try {
36
- update();
37
- } catch {}
38
- };
39
-
40
- try {
41
- update();
42
- watch(watchPath, listener);
43
- } catch {
44
- watchFile(watchPath, () => {
45
- try {
46
- update();
47
- watch(watchPath, listener);
48
- unwatchFile(watchPath);
49
- } catch {}
50
- });
51
- }
52
-
53
- const getSourceFile = fileName => languageService.getProgram()?.getSourceFile(fileName);
54
-
55
- const isGraphqlTag = tag => {
56
- switch (tag) {
57
- case "query":
58
- case "mutation":
59
- case "subscription":
60
- return true;
61
-
62
- default:
63
- return false;
64
- }
65
- };
66
-
67
- const getDiagnosticCategory = severity => {
68
- switch (severity) {
69
- case DiagnosticSeverity.Error:
70
- return ts.DiagnosticCategory.Error;
71
-
72
- case DiagnosticSeverity.Warning:
73
- return ts.DiagnosticCategory.Warning;
74
-
75
- case DiagnosticSeverity.Information:
76
- return ts.DiagnosticCategory.Message;
77
-
78
- case DiagnosticSeverity.Hint:
79
- return ts.DiagnosticCategory.Suggestion;
80
-
81
- default:
82
- return ts.DiagnosticCategory.Error;
83
- }
84
- };
85
-
86
- const hover = (sourceFile, position) => {
87
- const tag = ts.forEachChild(sourceFile, function visitor(node) {
88
- if (position < node.pos) {
89
- return true;
90
- }
91
-
92
- if (position >= node.end) {
93
- return;
94
- }
95
-
96
- if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && isGraphqlTag(node.tag.getText())) {
97
- const template = node.template;
98
-
99
- if (ts.isNoSubstitutionTemplateLiteral(template)) {
100
- if (position >= template.getStart() + 1 && position < template.getEnd() - 1) {
101
- return node;
102
- }
103
- } else {
104
- const head = template.head;
105
-
106
- if (position >= head.getStart() + 1 && position < head.getEnd() - 2) {
107
- return node;
108
- }
109
-
110
- for (const {
111
- literal
112
- } of template.templateSpans) {
113
- if (position >= literal.getStart() + 1 && position < literal.getEnd() - (ts.isTemplateMiddle(literal) ? 2 : 1)) {
114
- return node;
9
+ const init = ({ typescript: ts }) => {
10
+ return {
11
+ create(info) {
12
+ const languageService = info.languageService;
13
+ const config = info.config;
14
+ const cwd = info.project.getCurrentDirectory();
15
+ const modelPath = config.model && resolve(cwd, config.model);
16
+ const schemaPath = config.schema && resolve(cwd, config.schema);
17
+ const watchPath = modelPath || schemaPath;
18
+ let schema = buildSchema("scalar Unknown");
19
+ const addScalarUnknownType = (schemaCode) => schemaCode.includes("scalar Unknown") ? schemaCode : `${schemaCode}\nscalar Unknown`;
20
+ const changeModel = () => {
21
+ schema = buildSchema(addScalarUnknownType(printSchemaModel(readFileSync(modelPath, "utf8"))));
22
+ };
23
+ const changeSchema = () => {
24
+ schema = buildSchema(addScalarUnknownType(readFileSync(schemaPath, "utf8")));
25
+ };
26
+ const update = modelPath ? changeModel : changeSchema;
27
+ const listener = () => {
28
+ try {
29
+ update();
115
30
  }
116
- }
117
- }
118
- }
119
-
120
- return ts.forEachChild(node, visitor);
121
- });
122
-
123
- if (tag === true) {
124
- return;
125
- }
126
-
127
- return tag;
128
- };
129
-
130
- const fix = node => {
131
- const template = node.template;
132
- let query = "";
133
- let variables = "";
134
-
135
- if (ts.isNoSubstitutionTemplateLiteral(template)) {
136
- // 2 ``
137
- const templateWidth = template.getWidth() - 2;
138
- query = template.text.padStart(templateWidth);
139
- } else {
140
- const head = template.head;
141
- const templateSpans = template.templateSpans; // 3 `...${
142
-
143
- const templateWidth = head.getWidth() - 3;
144
- query = head.text.padStart(templateWidth);
145
- templateSpans.forEach((span, i) => {
146
- const spanWidth = span.getFullWidth();
147
- const literal = span.literal;
148
- const literalWidth = literal.getWidth();
149
- const expressionWidth = spanWidth - literalWidth;
150
- const variableName = `$_${i}`;
151
- const variable = variableName.padStart(expressionWidth + 2).padEnd(expressionWidth + 3);
152
- const templateWidth = literalWidth - (ts.isTemplateTail(literal) ? 2 : 3);
153
- const template = literal.text.padStart(templateWidth);
154
- query += variable + template;
155
- variables += variableName + ":Unknown";
156
- });
157
- }
158
-
159
- const tag = node.tag.getText();
160
- let offset = template.getStart() + 1;
161
- query = query.replace(/\n|\r/g, " ");
162
-
163
- if (variables) {
164
- query = `${tag}(${variables}){${query}}`;
165
- offset -= tag.length + variables.length + 3;
166
- } else if (tag === "query") {
167
- query = `{${query}}`;
168
- offset -= 1;
169
- } else {
170
- query = `${tag}{${query}}`;
171
- offset -= tag.length + 1;
172
- }
173
-
174
- const documentNode = parse(query);
175
- const errors = validate(schema, documentNode);
176
-
177
- for (const error of errors) {
178
- const match = error.message.match(/^Variable ".*?" of type "Unknown" used in position expecting type "(.*?)"\.$/);
179
-
180
- if (match) {
181
- query = query.replace("Unknown", match[1]);
182
- offset += 7 - match[1].length;
183
- }
184
- }
185
-
186
- return {
187
- query,
188
- offset
189
- };
190
- };
191
-
192
- const proxy = Object.create(null);
193
-
194
- for (const [key, value] of Object.entries(languageService)) {
195
- proxy[key] = value.bind(languageService);
196
- }
197
-
198
- proxy.getQuickInfoAtPosition = (fileName, position) => {
199
- const sourceFile = getSourceFile(fileName);
200
-
201
- if (!sourceFile) {
202
- return undefined;
203
- }
204
-
205
- const tag = hover(sourceFile, position);
206
-
207
- if (!tag) {
208
- return languageService.getQuickInfoAtPosition(fileName, position);
209
- }
210
-
211
- let result;
212
-
213
- try {
214
- result = fix(tag);
215
- } catch {
216
- return languageService.getQuickInfoAtPosition(fileName, position);
217
- }
218
-
219
- const {
220
- query,
221
- offset
222
- } = result;
223
- const cursor = new Position(0, position - offset + 1);
224
- const token = getTokenAtPosition(query, cursor);
225
- const marked = getHoverInformation(schema, query, cursor, token);
226
-
227
- if (marked === "" || typeof marked !== "string") {
228
- return;
229
- }
230
-
231
- return {
232
- kind: ts.ScriptElementKind.string,
233
- textSpan: {
234
- start: offset + token.start,
235
- length: token.end - token.start
236
- },
237
- kindModifiers: "",
238
- displayParts: [{
239
- text: marked,
240
- kind: ""
241
- }]
242
- };
243
- };
244
-
245
- proxy.getCompletionsAtPosition = (fileName, position, options) => {
246
- const sourceFile = getSourceFile(fileName);
247
-
248
- if (!sourceFile) {
249
- return undefined;
250
- }
251
-
252
- const tag = hover(sourceFile, position);
253
-
254
- if (!tag) {
255
- return languageService.getCompletionsAtPosition(fileName, position, options);
256
- }
257
-
258
- let result;
259
-
260
- try {
261
- result = fix(tag);
262
- } catch {
263
- return languageService.getCompletionsAtPosition(fileName, position, options);
264
- }
265
-
266
- const {
267
- query,
268
- offset
269
- } = result;
270
- const cursor = new Position(0, position - offset);
271
- const token = getTokenAtPosition(query, cursor);
272
- const items = getAutocompleteSuggestions(schema, query, cursor, token);
273
-
274
- if (!items.length) {
275
- return;
276
- }
277
-
278
- return {
279
- isGlobalCompletion: false,
280
- isMemberCompletion: false,
281
- isNewIdentifierLocation: false,
282
- entries: items.map(item => {
283
- let kind;
284
-
285
- switch (item.kind) {
286
- case CompletionItemKind.Function:
287
- case CompletionItemKind.Constructor:
288
- kind = ts.ScriptElementKind.functionElement;
289
- break;
290
-
291
- case CompletionItemKind.Field:
292
- case CompletionItemKind.Variable:
293
- kind = ts.ScriptElementKind.memberVariableElement;
294
- break;
295
-
296
- default:
297
- kind = ts.ScriptElementKind.unknown;
298
- break;
299
- }
300
-
301
- return {
302
- name: item.label,
303
- kindModifiers: "",
304
- kind,
305
- sortText: ""
31
+ catch { }
306
32
  };
307
- })
308
- };
309
- };
310
-
311
- proxy.getSemanticDiagnostics = fileName => {
312
- const diagnostics = languageService.getSemanticDiagnostics(fileName);
313
- const sourceFile = getSourceFile(fileName);
314
-
315
- if (!sourceFile) {
316
- return diagnostics;
317
- }
318
-
319
- ts.forEachChild(sourceFile, function visitor(node) {
320
- if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && isGraphqlTag(node.tag.getText())) {
321
33
  try {
322
- const {
323
- query,
324
- offset
325
- } = fix(node);
326
-
327
- const _diagnostics = getDiagnostics(query, schema);
328
-
329
- for (const {
330
- range: {
331
- start,
332
- end
333
- },
334
- severity,
335
- message
336
- } of _diagnostics) {
337
- diagnostics.push({
338
- category: getDiagnosticCategory(severity),
339
- code: 9999,
340
- messageText: message,
341
- file: sourceFile,
342
- start: start.character + offset,
343
- length: end.character - start.character
34
+ update();
35
+ watch(watchPath, listener);
36
+ }
37
+ catch {
38
+ watchFile(watchPath, () => {
39
+ try {
40
+ update();
41
+ watch(watchPath, listener);
42
+ unwatchFile(watchPath);
43
+ }
44
+ catch { }
344
45
  });
345
- }
346
- } catch (error) {
347
- if (error instanceof GraphQLError) {
348
- diagnostics.push({
349
- category: ts.DiagnosticCategory.Error,
350
- code: 9999,
351
- messageText: error.message,
352
- file: sourceFile,
353
- start: node.template.getStart() + 1,
354
- length: node.template.getWidth() - 2
46
+ }
47
+ const getSourceFile = (fileName) => languageService.getProgram()?.getSourceFile(fileName);
48
+ const isGraphqlTag = (tag) => {
49
+ switch (tag) {
50
+ case "query":
51
+ case "mutation":
52
+ case "subscription":
53
+ return true;
54
+ default:
55
+ return false;
56
+ }
57
+ };
58
+ const getDiagnosticCategory = (severity) => {
59
+ switch (severity) {
60
+ case DiagnosticSeverity.Error:
61
+ return ts.DiagnosticCategory.Error;
62
+ case DiagnosticSeverity.Warning:
63
+ return ts.DiagnosticCategory.Warning;
64
+ case DiagnosticSeverity.Information:
65
+ return ts.DiagnosticCategory.Message;
66
+ case DiagnosticSeverity.Hint:
67
+ return ts.DiagnosticCategory.Suggestion;
68
+ default:
69
+ return ts.DiagnosticCategory.Error;
70
+ }
71
+ };
72
+ const hover = (sourceFile, position) => {
73
+ const tag = ts.forEachChild(sourceFile, function visitor(node) {
74
+ if (position < node.pos) {
75
+ return true;
76
+ }
77
+ if (position >= node.end) {
78
+ return;
79
+ }
80
+ if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && isGraphqlTag(node.tag.getText())) {
81
+ const template = node.template;
82
+ if (ts.isNoSubstitutionTemplateLiteral(template)) {
83
+ if (position >= template.getStart() + 1 && position < template.getEnd() - 1) {
84
+ return node;
85
+ }
86
+ }
87
+ else {
88
+ const head = template.head;
89
+ if (position >= head.getStart() + 1 && position < head.getEnd() - 2) {
90
+ return node;
91
+ }
92
+ for (const { literal } of template.templateSpans) {
93
+ if (position >= literal.getStart() + 1 &&
94
+ position < literal.getEnd() - (ts.isTemplateMiddle(literal) ? 2 : 1)) {
95
+ return node;
96
+ }
97
+ }
98
+ }
99
+ }
100
+ return ts.forEachChild(node, visitor);
355
101
  });
356
- }
102
+ if (tag === true) {
103
+ return;
104
+ }
105
+ return tag;
106
+ };
107
+ const fix = (node) => {
108
+ const template = node.template;
109
+ let query = "";
110
+ let variables = "";
111
+ if (ts.isNoSubstitutionTemplateLiteral(template)) {
112
+ // 2 ``
113
+ const templateWidth = template.getWidth() - 2;
114
+ query = template.text.padStart(templateWidth);
115
+ }
116
+ else {
117
+ const head = template.head;
118
+ const templateSpans = template.templateSpans;
119
+ // 3 `...${
120
+ const templateWidth = head.getWidth() - 3;
121
+ query = head.text.padStart(templateWidth);
122
+ templateSpans.forEach((span, i) => {
123
+ const spanWidth = span.getFullWidth();
124
+ const literal = span.literal;
125
+ const literalWidth = literal.getWidth();
126
+ const expressionWidth = spanWidth - literalWidth;
127
+ const variableName = `$_${i}`;
128
+ const variable = variableName.padStart(expressionWidth + 2).padEnd(expressionWidth + 3);
129
+ const templateWidth = literalWidth - (ts.isTemplateTail(literal) ? 2 : 3);
130
+ const template = literal.text.padStart(templateWidth);
131
+ query += variable + template;
132
+ variables += variableName + ":Unknown";
133
+ });
134
+ }
135
+ const tag = node.tag.getText();
136
+ let offset = template.getStart() + 1;
137
+ query = query.replace(/\n|\r/g, " ");
138
+ if (variables) {
139
+ query = `${tag}(${variables}){${query}}`;
140
+ offset -= tag.length + variables.length + 3;
141
+ }
142
+ else if (tag === "query") {
143
+ query = `{${query}}`;
144
+ offset -= 1;
145
+ }
146
+ else {
147
+ query = `${tag}{${query}}`;
148
+ offset -= tag.length + 1;
149
+ }
150
+ const documentNode = parse(query);
151
+ const errors = validate(schema, documentNode);
152
+ for (const error of errors) {
153
+ const match = error.message.match(/^Variable ".*?" of type "Unknown" used in position expecting type "(.*?)"\.$/);
154
+ if (match) {
155
+ query = query.replace("Unknown", match[1]);
156
+ offset += 7 - match[1].length;
157
+ }
158
+ }
159
+ return {
160
+ query,
161
+ offset,
162
+ };
163
+ };
164
+ const proxy = Object.create(null);
165
+ for (const [key, value] of Object.entries(languageService)) {
166
+ proxy[key] = value.bind(languageService);
357
167
  }
358
- }
359
-
360
- ts.forEachChild(node, visitor);
361
- });
362
- return diagnostics;
363
- };
364
-
365
- return proxy;
366
- }
367
-
368
- };
168
+ proxy.getQuickInfoAtPosition = (fileName, position) => {
169
+ const sourceFile = getSourceFile(fileName);
170
+ if (!sourceFile) {
171
+ return undefined;
172
+ }
173
+ const tag = hover(sourceFile, position);
174
+ if (!tag) {
175
+ return languageService.getQuickInfoAtPosition(fileName, position);
176
+ }
177
+ let result;
178
+ try {
179
+ result = fix(tag);
180
+ }
181
+ catch {
182
+ return languageService.getQuickInfoAtPosition(fileName, position);
183
+ }
184
+ const { query, offset } = result;
185
+ const cursor = new Position(0, position - offset + 1);
186
+ const token = getTokenAtPosition(query, cursor);
187
+ const marked = getHoverInformation(schema, query, cursor, token);
188
+ if (marked === "" || typeof marked !== "string") {
189
+ return;
190
+ }
191
+ return {
192
+ kind: ts.ScriptElementKind.string,
193
+ textSpan: {
194
+ start: offset + token.start,
195
+ length: token.end - token.start,
196
+ },
197
+ kindModifiers: "",
198
+ displayParts: [{ text: marked, kind: "" }],
199
+ };
200
+ };
201
+ proxy.getCompletionsAtPosition = (fileName, position, options) => {
202
+ const sourceFile = getSourceFile(fileName);
203
+ if (!sourceFile) {
204
+ return undefined;
205
+ }
206
+ const tag = hover(sourceFile, position);
207
+ if (!tag) {
208
+ return languageService.getCompletionsAtPosition(fileName, position, options);
209
+ }
210
+ let result;
211
+ try {
212
+ result = fix(tag);
213
+ }
214
+ catch {
215
+ return languageService.getCompletionsAtPosition(fileName, position, options);
216
+ }
217
+ const { query, offset } = result;
218
+ const cursor = new Position(0, position - offset);
219
+ const token = getTokenAtPosition(query, cursor);
220
+ const items = getAutocompleteSuggestions(schema, query, cursor, token);
221
+ if (!items.length) {
222
+ return;
223
+ }
224
+ return {
225
+ isGlobalCompletion: false,
226
+ isMemberCompletion: false,
227
+ isNewIdentifierLocation: false,
228
+ entries: items.map((item) => {
229
+ let kind;
230
+ switch (item.kind) {
231
+ case CompletionItemKind.Function:
232
+ case CompletionItemKind.Constructor:
233
+ kind = ts.ScriptElementKind.functionElement;
234
+ break;
235
+ case CompletionItemKind.Field:
236
+ case CompletionItemKind.Variable:
237
+ kind = ts.ScriptElementKind.memberVariableElement;
238
+ break;
239
+ default:
240
+ kind = ts.ScriptElementKind.unknown;
241
+ break;
242
+ }
243
+ return {
244
+ name: item.label,
245
+ kindModifiers: "",
246
+ kind,
247
+ sortText: "",
248
+ };
249
+ }),
250
+ };
251
+ };
252
+ proxy.getSemanticDiagnostics = (fileName) => {
253
+ const diagnostics = languageService.getSemanticDiagnostics(fileName);
254
+ const sourceFile = getSourceFile(fileName);
255
+ if (!sourceFile) {
256
+ return diagnostics;
257
+ }
258
+ ts.forEachChild(sourceFile, function visitor(node) {
259
+ if (ts.isTaggedTemplateExpression(node) && ts.isIdentifier(node.tag) && isGraphqlTag(node.tag.getText())) {
260
+ try {
261
+ const { query, offset } = fix(node);
262
+ const _diagnostics = getDiagnostics(query, schema);
263
+ for (const { range: { start, end }, severity, message, } of _diagnostics) {
264
+ diagnostics.push({
265
+ category: getDiagnosticCategory(severity),
266
+ code: 9999,
267
+ messageText: message,
268
+ file: sourceFile,
269
+ start: start.character + offset,
270
+ length: end.character - start.character,
271
+ });
272
+ }
273
+ }
274
+ catch (error) {
275
+ if (error instanceof GraphQLError) {
276
+ diagnostics.push({
277
+ category: ts.DiagnosticCategory.Error,
278
+ code: 9999,
279
+ messageText: error.message,
280
+ file: sourceFile,
281
+ start: node.template.getStart() + 1,
282
+ length: node.template.getWidth() - 2,
283
+ });
284
+ }
285
+ }
286
+ }
287
+ ts.forEachChild(node, visitor);
288
+ });
289
+ return diagnostics;
290
+ };
291
+ return proxy;
292
+ },
293
+ };
369
294
  };
370
295
 
371
- export default init;
296
+ export { init as default };
372
297
  //# sourceMappingURL=index.mjs.map