Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support queries for multiple schemas in the same file #3411

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions packages/graphql-language-service-server/src/GraphQLCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@ import glob from 'glob';
import { LoadConfigOptions } from './types';
import { URI } from 'vscode-uri';
import { CodeFileLoader } from '@graphql-tools/code-file-loader';
import { EXTENSION_NAME } from './GraphQLLanguageService';

const LanguageServiceExtension: GraphQLExtensionDeclaration = api => {
export const LanguageServiceExtension: GraphQLExtensionDeclaration = api => {
// For schema
api.loaders.schema.register(new CodeFileLoader());
// For documents
api.loaders.documents.register(new CodeFileLoader());

return { name: 'languageService' };
return { name: EXTENSION_NAME };
};

// Maximum files to read when processing GraphQL files.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
SymbolKind,
} from 'vscode-languageserver-types';

import { fileURLToPath } from 'node:url';

export const EXTENSION_NAME = 'languageService';

const KIND_TO_SYMBOL_KIND: { [key: string]: SymbolKind } = {
[Kind.FIELD]: SymbolKind.Field,
[Kind.OPERATION_DEFINITION]: SymbolKind.Class,
Expand Down Expand Up @@ -96,11 +100,38 @@
this._logger = logger;
}

getConfigForURI(uri: Uri) {
const config = this._graphQLCache.getProjectForFile(uri);
if (config) {
return config;
getAllProjectsForFile(uri: Uri) {
const filePath = uri.startsWith('file:') ? fileURLToPath(uri) : uri;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Passing an Uri that starts with the file:// protocol doesn't work properly in grahiQLConfig.getProjectForFile. Internally that calls minimatch and it always returns false.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes there was a breaking change in vscode some years ago, and there are a few places that we didn't handle this, thanks for the bugfix! I will come back around look at the implementations because they should all be passing a file url

const projects = Object.values(this._graphQLConfig.projects).filter(
project => project.match(filePath),
);

return projects.length > 0
? projects
: // Fallback, this always finds at least 1 project
[this._graphQLConfig.getProjectForFile(filePath)];
}

getProjectForQuery(
query: string,
uri: Uri,
projects?: GraphQLProjectConfig[],
) {
if (!query.startsWith('#graphql')) {
// Query is not annotated with #graphql.
// Skip suffix check and return the first project that matches the file.
return projects?.[0] ?? this._graphQLConfig.getProjectForFile(uri);
}
frandiox marked this conversation as resolved.
Show resolved Hide resolved

return (projects || this.getAllProjectsForFile(uri)).find(project => {
const ext = project.hasExtension(EXTENSION_NAME)
? project.extension(EXTENSION_NAME)
: null;

const suffix = ext?.gqlTagOptions?.annotationSuffix;

return query.startsWith(`#graphql${suffix ? ':' + suffix : ''}\n`);
});
}

public async getDiagnostics(
Expand All @@ -111,7 +142,7 @@
// Perform syntax diagnostics first, as this doesn't require
// schema/fragment definitions, even the project configuration.
let documentHasExtensions = false;
const projectConfig = this.getConfigForURI(uri);
const projectConfig = this.getProjectForQuery(document, uri);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rename this to getProjectForDocument ? just so people don't assume this only works with queries, as it should also work with SDL

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated! I've also resolved the new conflicts but fyi, there's a problem with cspell on commit because it finds unknown words in .vscode/settings.json.

// skip validation when there's nothing to validate, prevents noisy unexpected EOF errors
if (!projectConfig || !document || document.trim().length < 2) {
return [];
Expand Down Expand Up @@ -218,7 +249,7 @@
position: IPosition,
filePath: Uri,
): Promise<Array<CompletionItem>> {
const projectConfig = this.getConfigForURI(filePath);
const projectConfig = this.getProjectForQuery(query, filePath);

Check warning on line 252 in packages/graphql-language-service-server/src/GraphQLLanguageService.ts

View check run for this annotation

Codecov / codecov/patch

packages/graphql-language-service-server/src/GraphQLLanguageService.ts#L252

Added line #L252 was not covered by tests
if (!projectConfig) {
return [];
}
Expand Down Expand Up @@ -255,7 +286,7 @@
filePath: Uri,
options?: HoverConfig,
): Promise<Hover['contents']> {
const projectConfig = this.getConfigForURI(filePath);
const projectConfig = this.getProjectForQuery(query, filePath);
if (!projectConfig) {
return '';
}
Expand All @@ -272,7 +303,7 @@
position: IPosition,
filePath: Uri,
): Promise<DefinitionQueryResult | null> {
const projectConfig = this.getConfigForURI(filePath);
const projectConfig = this.getProjectForQuery(query, filePath);
if (!projectConfig) {
return null;
}
Expand Down