Skip to content
This repository was archived by the owner on Jul 31, 2022. It is now read-only.

Commit 93ca640

Browse files
author
Divyendu Singh
authored
feat(CodeLens): and configuration fixes (#58)
* bump: version for 0.0.10 * feat: codelens without query * feat: inline playground and codelens * feat: codelens, extract graphql response from apollo response * feat: codelens, ignore template variables for now * fix: regex * bump version for release * fix: configuration, update deps * fix: deps * fix: add codelens only for executable operations * bump version * fix: support scalars, code clean up * fix: codelens, add support for object type * fix: codegen, handle lists as input * fix: codelens, constructor * bump version for internal release * dep: add subscriptions-transport-ws * fix: add catch brackets * fix: added parameter to constructor * chore: add fish shell support * chore: bump version * fix: race condition between input and content provider * bump version * beta: mark as preview * bump version
1 parent d36a11f commit 93ca640

9 files changed

+1373
-621
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ Setup and logging for development are different for these language services as d
113113
export TSS_LOG="-logToFile true -file <absolute-path> -level verbose"
114114
cd <graphql-project-path>
115115
code .
116-
tail -f <absolute-path> | grep [\"ts-graphql-plugin\"]
116+
tail -f <absolute-path> | grep ts-graphql-plugin-log
117117
```
118118
119119
## License

package-lock.json

Lines changed: 826 additions & 607 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
{
22
"name": "vscode-graphql",
3+
"version": "0.1.4",
4+
"preview": true,
35
"private": false,
46
"license": "MIT",
57
"displayName": "GraphQL",
8+
"keywords": [
9+
"multi-root ready"
10+
],
611
"description": "GraphQL extension for VSCode adds syntax highlighting, validation, and language features like go to definition, hover information and autocompletion for graphql projects. This extension also works with queries annotated with gql tag.",
712
"icon": "assets/images/logo.png",
813
"repository": {
@@ -14,10 +19,9 @@
1419
"color": "#032539",
1520
"theme": "dark"
1621
},
17-
"version": "0.0.9",
1822
"publisher": "Prisma",
1923
"engines": {
20-
"vscode": "^1.23.0"
24+
"vscode": "^1.25.0"
2125
},
2226
"categories": [
2327
"Programming Languages",
@@ -28,6 +32,7 @@
2832
],
2933
"activationEvents": [
3034
"onCommand:extension.isDebugging",
35+
"onCommand:extension.contentProvider",
3136
"onLanguage:graphql",
3237
"workspaceContains:**/.graphqlconfig",
3338
"workspaceContains:**/.graphqlconfig.yml",
@@ -99,6 +104,10 @@
99104
{
100105
"command": "extension.isDebugging",
101106
"title": "VSCode GraphQL - Is Debugging?"
107+
},
108+
{
109+
"command": "extension.contentProvider",
110+
"title": "Execute GraphQL Operations"
102111
}
103112
],
104113
"typescriptServerPlugins": [
@@ -109,26 +118,38 @@
109118
},
110119
"scripts": {
111120
"vscode:prepublish": "npm run compile",
112-
"compile": "rimraf out && tsc -p ./",
121+
"compile": "tsc -p ./",
113122
"watch": "tsc -watch -p ./",
114123
"postinstall": "node ./node_modules/vscode/bin/install",
115124
"test": "npm run compile && node ./node_modules/vscode/bin/test",
116125
"package": "vsce package"
117126
},
118127
"devDependencies": {
119-
"@types/graphql": "0.12.3",
128+
"@types/capitalize": "^1.0.1",
129+
"@types/graphql": "0.13.2",
120130
"@types/mocha": "^2.2.42",
121131
"@types/node": "^7.0.43",
132+
"@types/ws": "^5.1.2",
122133
"tslint": "^5.8.0",
123134
"typescript": "^2.6.1",
135+
"vsce": "^1.45.1",
124136
"vscode": "^1.1.6"
125137
},
126138
"dependencies": {
127-
"@divyenduz/ts-graphql-plugin": "0.0.6",
139+
"@divyenduz/graphql-language-service-server": "1.2.6",
140+
"@divyenduz/ts-graphql-plugin": "0.1.0",
141+
"apollo-cache-inmemory": "^1.2.6",
142+
"apollo-client": "2.3.5",
143+
"apollo-link-ws": "^1.0.8",
128144
"babel-polyfill": "^6.26.0",
129-
"graphql": "0.12.3",
145+
"capitalize": "^1.0.0",
146+
"graphql": "0.13.2",
147+
"graphql-config": "^2.1.0",
130148
"graphql-config-extension-prisma": "0.1.0",
131-
"@divyenduz/graphql-language-service-server": "1.2.3",
132-
"vscode-languageclient": "^4.1.3"
149+
"graphql-tag": "^2.9.2",
150+
"http-link-dataloader": "^0.1.3",
151+
"subscriptions-transport-ws": "^0.9.14",
152+
"vscode-languageclient": "^4.1.3",
153+
"ws": "^6.0.0"
133154
}
134155
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import {
2+
OutputChannel,
3+
CodeLensProvider,
4+
TextDocument,
5+
CancellationToken,
6+
CodeLens,
7+
Range,
8+
Position,
9+
} from "vscode"
10+
11+
import { SourceHelper, ExtractedTemplateLiteral } from "./source-helper"
12+
import { OperationDefinitionNode } from "graphql"
13+
import * as capitalize from "capitalize"
14+
15+
export class GraphQLCodeLensProvider implements CodeLensProvider {
16+
outputChannel: OutputChannel
17+
sourceHelper: SourceHelper
18+
19+
constructor(outputChannel: OutputChannel) {
20+
this.outputChannel = outputChannel
21+
this.sourceHelper = new SourceHelper(this.outputChannel)
22+
}
23+
24+
public provideCodeLenses(
25+
document: TextDocument,
26+
token: CancellationToken,
27+
): CodeLens[] | Thenable<CodeLens[]> {
28+
const literals: ExtractedTemplateLiteral[] = this.sourceHelper.extractAllTemplateLiterals(
29+
document,
30+
["gql", "graphql"],
31+
)
32+
return literals.map(literal => {
33+
return new CodeLens(
34+
new Range(
35+
new Position(literal.position.line, 0),
36+
new Position(literal.position.line, 0),
37+
),
38+
{
39+
title: `Execute ${capitalize(
40+
(literal.ast.definitions[0] as OperationDefinitionNode).operation,
41+
)}`,
42+
command: "extension.contentProvider",
43+
arguments: [literal],
44+
},
45+
)
46+
})
47+
}
48+
}
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import {
2+
workspace,
3+
OutputChannel,
4+
TextDocumentContentProvider,
5+
EventEmitter,
6+
Uri,
7+
Event,
8+
ProviderResult,
9+
window
10+
} from "vscode";
11+
12+
import { ExtractedTemplateLiteral } from "./source-helper";
13+
import {
14+
GraphQLConfig,
15+
getGraphQLConfig,
16+
GraphQLProjectConfig
17+
} from "graphql-config";
18+
import { visit, VariableDefinitionNode } from "graphql";
19+
import { NetworkHelper } from "./network-helper";
20+
import { SourceHelper, GraphQLScalarTSType } from "./source-helper";
21+
22+
export class GraphQLContentProvider implements TextDocumentContentProvider {
23+
private uri: Uri;
24+
private outputChannel: OutputChannel;
25+
private networkHelper: NetworkHelper;
26+
private sourceHelper: SourceHelper;
27+
28+
// Event emitter which invokes document updates
29+
private _onDidChange = new EventEmitter<Uri>();
30+
31+
private html: string = ""; // HTML document buffer
32+
33+
timeout = ms => new Promise(res => setTimeout(res, ms));
34+
35+
async getVariablesFromUser(
36+
variableDefinitionNodes: VariableDefinitionNode[]
37+
): Promise<{ [key: string]: GraphQLScalarTSType }> {
38+
await this.timeout(500);
39+
let variables = {};
40+
for (let node of variableDefinitionNodes) {
41+
variables = {
42+
...variables,
43+
[`${node.variable.name.value}`]: this.sourceHelper.typeCast(
44+
await window.showInputBox({
45+
ignoreFocusOut: true,
46+
placeHolder: `Please enter the value for ${
47+
node.variable.name.value
48+
}`
49+
}),
50+
this.sourceHelper.getTypeForVariableDefinitionNode(node)
51+
)
52+
};
53+
}
54+
return variables;
55+
}
56+
57+
/*
58+
Use the configration of first project if heuristics failed
59+
to find one.
60+
*/
61+
patchProjectConfig(config: GraphQLConfig) {
62+
if (!config.config.projects) {
63+
return config;
64+
}
65+
if (config.config.projects) {
66+
const projectKeys = Object.keys(config.config.projects);
67+
return config.getProjectConfig(projectKeys[0]);
68+
}
69+
return null;
70+
}
71+
72+
constructor(
73+
uri: Uri,
74+
outputChannel: OutputChannel,
75+
literal: ExtractedTemplateLiteral
76+
) {
77+
this.uri = uri;
78+
this.outputChannel = outputChannel;
79+
this.networkHelper = new NetworkHelper(this.outputChannel);
80+
this.sourceHelper = new SourceHelper(this.outputChannel);
81+
82+
try {
83+
const rootDir = workspace.getWorkspaceFolder(Uri.file(literal.uri));
84+
if (!rootDir) {
85+
this.outputChannel.appendLine(
86+
`Error: this file is outside the workspace.`
87+
);
88+
this.html = "Error: this file is outside the workspace.";
89+
this.update(this.uri);
90+
return;
91+
} else {
92+
const config = getGraphQLConfig(rootDir!.uri.fsPath);
93+
let projectConfig = config.getConfigForFile(literal.uri);
94+
if (!projectConfig) {
95+
projectConfig = this.patchProjectConfig(
96+
config
97+
) as GraphQLProjectConfig;
98+
}
99+
100+
if (!projectConfig!.endpointsExtension) {
101+
this.outputChannel.appendLine(
102+
`Error: endpoint data missing from graphql config`
103+
);
104+
this.html = "Error: endpoint data missing from graphql config";
105+
this.update(this.uri);
106+
return;
107+
}
108+
109+
const endpointNames = Object.keys(
110+
projectConfig!.endpointsExtension!.getRawEndpointsMap()
111+
);
112+
113+
if (endpointNames.length === 0) {
114+
this.outputChannel.appendLine(
115+
`Error: endpoint data missing from graphql config endpoints extension`
116+
);
117+
this.html =
118+
"Error: endpoint data missing from graphql config endpoints extension";
119+
this.update(this.uri);
120+
return;
121+
}
122+
123+
// TODO: Can ask user for the endpoint if muliple exist
124+
// Endpoints extensions docs say that at least "default" will be there
125+
const endpointName = endpointNames[0];
126+
const endpoint = projectConfig!.endpointsExtension!.getEndpoint(
127+
endpointName
128+
);
129+
130+
let variableDefinitionNodes: VariableDefinitionNode[] = [];
131+
visit(literal.ast, {
132+
VariableDefinition(node: VariableDefinitionNode) {
133+
variableDefinitionNodes.push(node);
134+
}
135+
});
136+
137+
const updateCallback = (data: string, operation: string) => {
138+
if (operation === "subscription") {
139+
this.html = `<pre>${data}</pre>` + this.html;
140+
} else {
141+
this.html += `<pre>${data}</pre>`;
142+
}
143+
this.update(this.uri);
144+
};
145+
146+
if (variableDefinitionNodes.length > 0) {
147+
this.getVariablesFromUser(variableDefinitionNodes).then(
148+
(variables: any) => {
149+
this.networkHelper.executeOperation({
150+
endpoint: endpoint,
151+
literal: literal,
152+
variables: variables,
153+
updateCallback
154+
});
155+
}
156+
);
157+
} else {
158+
this.networkHelper.executeOperation({
159+
endpoint: endpoint,
160+
literal: literal,
161+
variables: {},
162+
updateCallback
163+
});
164+
}
165+
}
166+
} catch (e) {
167+
this.html = e.toString();
168+
}
169+
}
170+
171+
get onDidChange(): Event<Uri> {
172+
return this._onDidChange.event;
173+
}
174+
175+
public update(uri: Uri) {
176+
this._onDidChange.fire(uri);
177+
}
178+
179+
provideTextDocumentContent(_: Uri): ProviderResult<string> {
180+
return this.html;
181+
}
182+
}

0 commit comments

Comments
 (0)