Skip to content

Commit

Permalink
feat: improve codelens support, restart on config changes
Browse files Browse the repository at this point in the history
  • Loading branch information
acao committed Jan 9, 2024
1 parent d5028be commit 186c75a
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 35 deletions.
48 changes: 30 additions & 18 deletions packages/vscode-graphql-execution/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,30 +42,31 @@ export function activate(context: ExtensionContext) {
// const settings = workspace.getConfiguration("vscode-graphql-execution")
// let provider: GraphQLCodeLensProvider;
const registerCodeLens = () => {
context.subscriptions.push(
languages.registerCodeLensProvider(
[
'javascript',
'typescript',
'javascriptreact',
'typescriptreact',
'graphql',
],
new GraphQLCodeLensProvider(outputChannel),
),
const provider = languages.registerCodeLensProvider(
[
'javascript',
'typescript',
'javascriptreact',
'typescriptreact',
'graphql',
],
new GraphQLCodeLensProvider(outputChannel),
);
context.subscriptions.push(provider);
return provider;
};

// if (settings.showExecCodelens !== false) {
registerCodeLens();
const codeLensProvider = registerCodeLens();

// }

let commandContentProvider: GraphQLContentProvider;

const registerContentProvider = () => {
return commands.registerCommand(
const provider = commands.registerCommand(
'vscode-graphql-execution.contentProvider',
(literal: ExtractedTemplateLiteral) => {
async (literal: ExtractedTemplateLiteral) => {
const uri = Uri.parse('graphql://authority/graphql');

const panel = window.createWebviewPanel(
Expand All @@ -81,6 +82,7 @@ export function activate(context: ExtensionContext) {
literal,
panel,
);
await commandContentProvider.loadProvider();
const registration = workspace.registerTextDocumentContentProvider(
'graphql',
commandContentProvider,
Expand All @@ -89,23 +91,33 @@ export function activate(context: ExtensionContext) {
panel.webview.html = commandContentProvider.getCurrentHtml();
},
);
context.subscriptions.push(provider);
return provider;
};

const provider = registerContentProvider();
context.subscriptions.push(provider);
const contentProvider = registerContentProvider();

// workspace.onDidChangeConfiguration(async () => {
// // const newSettings = workspace.getConfiguration("vscode-graphql-execution")
// // if (newSettings.showExecCodeLens !== false) {
// commandContentProvider.dispose()
// provider.dispose();
// // }
// });

workspace.onDidSaveTextDocument(async e => {
if (
e.fileName.includes('graphql.config') ||
e.fileName.includes('graphqlrc')
) {
await commandContentProvider.loadConfig();
if (contentProvider) {
await contentProvider.dispose();
registerContentProvider();
}

if (codeLensProvider) {
await codeLensProvider.dispose();
registerCodeLens();
}
}
});
}
Expand Down
26 changes: 26 additions & 0 deletions packages/vscode-graphql-execution/src/helpers/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,11 +172,36 @@ export class SourceHelper {
} catch {}
}

const regExpInline = new RegExp(
'`[\\n\\r\\s]*#graphql+([\\s\\S]+?)`',
'mg',
);

let inlineResult: RegExpExecArray | null;

while ((inlineResult = regExpInline.exec(text)) !== null) {
const contents = inlineResult[1];

// https://regex101.com/r/KFMXFg/2
if (contents.match('/${(.+)?}/g')) {
// We are ignoring operations with template variables for now
continue;
}
try {
processGraphQLString(contents, inlineResult.index + 1);

// no-op on exception, so that non-parse-able source files
// don't break the extension while editing
} catch {}
}

for (const tag of tags) {
// https://regex101.com/r/Pd5PaU/2
const regExpGQL = new RegExp(tag + '\\s*`([\\s\\S]+?)`', 'mg');
// https://regex101.com/r/FvG9qc/1

let result: RegExpExecArray | null;

while ((result = regExpGQL.exec(text)) !== null) {
const contents = result[1];

Expand All @@ -199,6 +224,7 @@ export class SourceHelper {
const operations = ast.definitions.filter(
def => def.kind === 'OperationDefinition',
);

for (const operation of operations) {
const op = operation as any;
const filteredAst = {
Expand Down
22 changes: 18 additions & 4 deletions packages/vscode-graphql-execution/src/providers/exec-codelens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,41 @@ import {
CodeLens,
Range,
Position,
ProviderResult,
} from 'vscode';

import { SourceHelper, ExtractedTemplateLiteral } from '../helpers/source';
import capitalize from 'capitalize';
import { GraphQLContentProvider } from './exec-content';

export class GraphQLCodeLensProvider implements CodeLensProvider {
outputChannel: OutputChannel;
sourceHelper: SourceHelper;
contentProvider?: GraphQLContentProvider;

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

public provideCodeLenses(
public async provideCodeLenses(
document: TextDocument,
_token: CancellationToken,
// for some reason, ProviderResult<CodeLens[]> doesn't work here
// anymore after upgrading types
): ProviderResult<[]> {
): Promise<CodeLens[]> {
this.contentProvider = new GraphQLContentProvider(
document.uri,
this.outputChannel,
// @ts-expect-error
{ uri: document.uri.fsPath },
);
await this.contentProvider.loadConfig();
if (
!this.contentProvider.hasConfig ||
!(await this.contentProvider.loadEndpoint())
) {
return [];
}
const literals: ExtractedTemplateLiteral[] =
this.sourceHelper.extractAllTemplateLiterals(document, [
'gql',
Expand All @@ -47,6 +61,6 @@ export class GraphQLCodeLensProvider implements CodeLensProvider {
);
});

return results as ProviderResult<[]>;
return results;
}
}
28 changes: 15 additions & 13 deletions packages/vscode-graphql-execution/src/providers/exec-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
private outputChannel: OutputChannel;
private networkHelper: NetworkHelper;
private sourceHelper: SourceHelper;
private panel: WebviewPanel;
private panel?: WebviewPanel;
private rootDir: WorkspaceFolder | undefined;
private literal: ExtractedTemplateLiteral;
private _projectConfig: GraphQLProjectConfig | undefined;
Expand All @@ -48,7 +48,13 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
}

updatePanel() {
this.panel.webview.html = this.html;
if (this.panel) {
this.panel.webview.html = this.html;
}
}

public get hasConfig() {
return Boolean(this._projectConfig);
}

async getVariablesFromUser(
Expand Down Expand Up @@ -96,7 +102,7 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
uri: Uri,
outputChannel: OutputChannel,
literal: ExtractedTemplateLiteral,
panel: WebviewPanel,
panel?: WebviewPanel,
) {
this.uri = uri;
this.outputChannel = outputChannel;
Expand All @@ -106,16 +112,14 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
this.sourceHelper,
);
this.panel = panel;

this.rootDir = workspace.getWorkspaceFolder(Uri.file(literal.uri));
this.literal = literal;
this.panel.webview.options = {
enableScripts: true,
};

// eslint-disable-next-line promise/prefer-await-to-then -- can't use async in constructor
this.loadProvider().catch(err => {
this.html = err.toString();
});
if (this.panel) {
this.panel.webview.options = {
enableScripts: true,
};
}
}

validUrlFromSchema(pathOrUrl: string) {
Expand Down Expand Up @@ -169,7 +173,6 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
}
}
const endpointNames = Object.keys(endpoints);

if (endpointNames.length === 0) {
this.reportError(
'Error: endpoint data missing from graphql config endpoints extension',
Expand Down Expand Up @@ -252,7 +255,6 @@ export class GraphQLContentProvider implements TextDocumentContentProvider {
this.reportError('Error: this file is outside the workspace.');
return;
}

const config = await loadConfig({
rootDir: rootDir.uri.fsPath,
throwOnEmpty: false,
Expand Down

0 comments on commit 186c75a

Please sign in to comment.