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

Commit

Permalink
feat(CodeLens): and configuration fixes (#58)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Divyendu Singh authored Aug 18, 2018
1 parent d36a11f commit 93ca640
Show file tree
Hide file tree
Showing 9 changed files with 1,373 additions and 621 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Setup and logging for development are different for these language services as d
export TSS_LOG="-logToFile true -file <absolute-path> -level verbose"
cd <graphql-project-path>
code .
tail -f <absolute-path> | grep [\"ts-graphql-plugin\"]
tail -f <absolute-path> | grep ts-graphql-plugin-log
```
## License
Expand Down
1,433 changes: 826 additions & 607 deletions package-lock.json

Large diffs are not rendered by default.

37 changes: 29 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
{
"name": "vscode-graphql",
"version": "0.1.4",
"preview": true,
"private": false,
"license": "MIT",
"displayName": "GraphQL",
"keywords": [
"multi-root ready"
],
"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.",
"icon": "assets/images/logo.png",
"repository": {
Expand All @@ -14,10 +19,9 @@
"color": "#032539",
"theme": "dark"
},
"version": "0.0.9",
"publisher": "Prisma",
"engines": {
"vscode": "^1.23.0"
"vscode": "^1.25.0"
},
"categories": [
"Programming Languages",
Expand All @@ -28,6 +32,7 @@
],
"activationEvents": [
"onCommand:extension.isDebugging",
"onCommand:extension.contentProvider",
"onLanguage:graphql",
"workspaceContains:**/.graphqlconfig",
"workspaceContains:**/.graphqlconfig.yml",
Expand Down Expand Up @@ -99,6 +104,10 @@
{
"command": "extension.isDebugging",
"title": "VSCode GraphQL - Is Debugging?"
},
{
"command": "extension.contentProvider",
"title": "Execute GraphQL Operations"
}
],
"typescriptServerPlugins": [
Expand All @@ -109,26 +118,38 @@
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "rimraf out && tsc -p ./",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"postinstall": "node ./node_modules/vscode/bin/install",
"test": "npm run compile && node ./node_modules/vscode/bin/test",
"package": "vsce package"
},
"devDependencies": {
"@types/graphql": "0.12.3",
"@types/capitalize": "^1.0.1",
"@types/graphql": "0.13.2",
"@types/mocha": "^2.2.42",
"@types/node": "^7.0.43",
"@types/ws": "^5.1.2",
"tslint": "^5.8.0",
"typescript": "^2.6.1",
"vsce": "^1.45.1",
"vscode": "^1.1.6"
},
"dependencies": {
"@divyenduz/ts-graphql-plugin": "0.0.6",
"@divyenduz/graphql-language-service-server": "1.2.6",
"@divyenduz/ts-graphql-plugin": "0.1.0",
"apollo-cache-inmemory": "^1.2.6",
"apollo-client": "2.3.5",
"apollo-link-ws": "^1.0.8",
"babel-polyfill": "^6.26.0",
"graphql": "0.12.3",
"capitalize": "^1.0.0",
"graphql": "0.13.2",
"graphql-config": "^2.1.0",
"graphql-config-extension-prisma": "0.1.0",
"@divyenduz/graphql-language-service-server": "1.2.3",
"vscode-languageclient": "^4.1.3"
"graphql-tag": "^2.9.2",
"http-link-dataloader": "^0.1.3",
"subscriptions-transport-ws": "^0.9.14",
"vscode-languageclient": "^4.1.3",
"ws": "^6.0.0"
}
}
48 changes: 48 additions & 0 deletions src/client/graphql-codelens-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {
OutputChannel,
CodeLensProvider,
TextDocument,
CancellationToken,
CodeLens,
Range,
Position,
} from "vscode"

import { SourceHelper, ExtractedTemplateLiteral } from "./source-helper"
import { OperationDefinitionNode } from "graphql"
import * as capitalize from "capitalize"

export class GraphQLCodeLensProvider implements CodeLensProvider {
outputChannel: OutputChannel
sourceHelper: SourceHelper

constructor(outputChannel: OutputChannel) {
this.outputChannel = outputChannel
this.sourceHelper = new SourceHelper(this.outputChannel)
}

public provideCodeLenses(
document: TextDocument,
token: CancellationToken,
): CodeLens[] | Thenable<CodeLens[]> {
const literals: ExtractedTemplateLiteral[] = this.sourceHelper.extractAllTemplateLiterals(
document,
["gql", "graphql"],
)
return literals.map(literal => {
return new CodeLens(
new Range(
new Position(literal.position.line, 0),
new Position(literal.position.line, 0),
),
{
title: `Execute ${capitalize(
(literal.ast.definitions[0] as OperationDefinitionNode).operation,
)}`,
command: "extension.contentProvider",
arguments: [literal],
},
)
})
}
}
182 changes: 182 additions & 0 deletions src/client/graphql-content-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import {
workspace,
OutputChannel,
TextDocumentContentProvider,
EventEmitter,
Uri,
Event,
ProviderResult,
window
} from "vscode";

import { ExtractedTemplateLiteral } from "./source-helper";
import {
GraphQLConfig,
getGraphQLConfig,
GraphQLProjectConfig
} from "graphql-config";
import { visit, VariableDefinitionNode } from "graphql";
import { NetworkHelper } from "./network-helper";
import { SourceHelper, GraphQLScalarTSType } from "./source-helper";

export class GraphQLContentProvider implements TextDocumentContentProvider {
private uri: Uri;
private outputChannel: OutputChannel;
private networkHelper: NetworkHelper;
private sourceHelper: SourceHelper;

// Event emitter which invokes document updates
private _onDidChange = new EventEmitter<Uri>();

private html: string = ""; // HTML document buffer

timeout = ms => new Promise(res => setTimeout(res, ms));

async getVariablesFromUser(
variableDefinitionNodes: VariableDefinitionNode[]
): Promise<{ [key: string]: GraphQLScalarTSType }> {
await this.timeout(500);
let variables = {};
for (let node of variableDefinitionNodes) {
variables = {
...variables,
[`${node.variable.name.value}`]: this.sourceHelper.typeCast(
await window.showInputBox({
ignoreFocusOut: true,
placeHolder: `Please enter the value for ${
node.variable.name.value
}`
}),
this.sourceHelper.getTypeForVariableDefinitionNode(node)
)
};
}
return variables;
}

/*
Use the configration of first project if heuristics failed
to find one.
*/
patchProjectConfig(config: GraphQLConfig) {
if (!config.config.projects) {
return config;
}
if (config.config.projects) {
const projectKeys = Object.keys(config.config.projects);
return config.getProjectConfig(projectKeys[0]);
}
return null;
}

constructor(
uri: Uri,
outputChannel: OutputChannel,
literal: ExtractedTemplateLiteral
) {
this.uri = uri;
this.outputChannel = outputChannel;
this.networkHelper = new NetworkHelper(this.outputChannel);
this.sourceHelper = new SourceHelper(this.outputChannel);

try {
const rootDir = workspace.getWorkspaceFolder(Uri.file(literal.uri));
if (!rootDir) {
this.outputChannel.appendLine(
`Error: this file is outside the workspace.`
);
this.html = "Error: this file is outside the workspace.";
this.update(this.uri);
return;
} else {
const config = getGraphQLConfig(rootDir!.uri.fsPath);
let projectConfig = config.getConfigForFile(literal.uri);
if (!projectConfig) {
projectConfig = this.patchProjectConfig(
config
) as GraphQLProjectConfig;
}

if (!projectConfig!.endpointsExtension) {
this.outputChannel.appendLine(
`Error: endpoint data missing from graphql config`
);
this.html = "Error: endpoint data missing from graphql config";
this.update(this.uri);
return;
}

const endpointNames = Object.keys(
projectConfig!.endpointsExtension!.getRawEndpointsMap()
);

if (endpointNames.length === 0) {
this.outputChannel.appendLine(
`Error: endpoint data missing from graphql config endpoints extension`
);
this.html =
"Error: endpoint data missing from graphql config endpoints extension";
this.update(this.uri);
return;
}

// TODO: Can ask user for the endpoint if muliple exist
// Endpoints extensions docs say that at least "default" will be there
const endpointName = endpointNames[0];
const endpoint = projectConfig!.endpointsExtension!.getEndpoint(
endpointName
);

let variableDefinitionNodes: VariableDefinitionNode[] = [];
visit(literal.ast, {
VariableDefinition(node: VariableDefinitionNode) {
variableDefinitionNodes.push(node);
}
});

const updateCallback = (data: string, operation: string) => {
if (operation === "subscription") {
this.html = `<pre>${data}</pre>` + this.html;
} else {
this.html += `<pre>${data}</pre>`;
}
this.update(this.uri);
};

if (variableDefinitionNodes.length > 0) {
this.getVariablesFromUser(variableDefinitionNodes).then(
(variables: any) => {
this.networkHelper.executeOperation({
endpoint: endpoint,
literal: literal,
variables: variables,
updateCallback
});
}
);
} else {
this.networkHelper.executeOperation({
endpoint: endpoint,
literal: literal,
variables: {},
updateCallback
});
}
}
} catch (e) {
this.html = e.toString();
}
}

get onDidChange(): Event<Uri> {
return this._onDidChange.event;
}

public update(uri: Uri) {
this._onDidChange.fire(uri);
}

provideTextDocumentContent(_: Uri): ProviderResult<string> {
return this.html;
}
}
Loading

0 comments on commit 93ca640

Please sign in to comment.