UNPKG

graphql-language-service-server

Version:
281 lines 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GraphQLLanguageService = void 0; const graphql_1 = require("graphql"); const graphql_language_service_1 = require("graphql-language-service"); const vscode_languageserver_types_1 = require("vscode-languageserver-types"); const KIND_TO_SYMBOL_KIND = { [graphql_1.Kind.FIELD]: vscode_languageserver_types_1.SymbolKind.Field, [graphql_1.Kind.OPERATION_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Class, [graphql_1.Kind.FRAGMENT_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Class, [graphql_1.Kind.FRAGMENT_SPREAD]: vscode_languageserver_types_1.SymbolKind.Struct, [graphql_1.Kind.OBJECT_TYPE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Class, [graphql_1.Kind.ENUM_TYPE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Enum, [graphql_1.Kind.ENUM_VALUE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.EnumMember, [graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Class, [graphql_1.Kind.INPUT_VALUE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Field, [graphql_1.Kind.FIELD_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Field, [graphql_1.Kind.INTERFACE_TYPE_DEFINITION]: vscode_languageserver_types_1.SymbolKind.Interface, [graphql_1.Kind.DOCUMENT]: vscode_languageserver_types_1.SymbolKind.File, FieldWithArguments: vscode_languageserver_types_1.SymbolKind.Method, }; function getKind(tree) { if (tree.kind === 'FieldDefinition' && tree.children && tree.children.length > 0) { return KIND_TO_SYMBOL_KIND.FieldWithArguments; } return KIND_TO_SYMBOL_KIND[tree.kind]; } class GraphQLLanguageService { constructor(cache, logger) { this._graphQLCache = cache; this._graphQLConfig = cache.getGraphQLConfig(); this._logger = logger; } getConfigForURI(uri) { const config = this._graphQLCache.getProjectForFile(uri); if (config) { return config; } } async getDiagnostics(document, uri, isRelayCompatMode) { var _a, _b; let documentHasExtensions = false; const projectConfig = this.getConfigForURI(uri); if (!projectConfig || !document || document.trim().length < 2) { return []; } const { schema: schemaPath, name: projectName, extensions } = projectConfig; try { const documentAST = (0, graphql_1.parse)(document); if (!schemaPath || uri !== schemaPath) { documentHasExtensions = documentAST.definitions.some(definition => { switch (definition.kind) { case graphql_1.Kind.OBJECT_TYPE_DEFINITION: case graphql_1.Kind.INTERFACE_TYPE_DEFINITION: case graphql_1.Kind.ENUM_TYPE_DEFINITION: case graphql_1.Kind.UNION_TYPE_DEFINITION: case graphql_1.Kind.SCALAR_TYPE_DEFINITION: case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION: case graphql_1.Kind.SCALAR_TYPE_EXTENSION: case graphql_1.Kind.OBJECT_TYPE_EXTENSION: case graphql_1.Kind.INTERFACE_TYPE_EXTENSION: case graphql_1.Kind.UNION_TYPE_EXTENSION: case graphql_1.Kind.ENUM_TYPE_EXTENSION: case graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION: case graphql_1.Kind.DIRECTIVE_DEFINITION: return true; } return false; }); } } catch (error) { if (error instanceof graphql_1.GraphQLError) { const range = (0, graphql_language_service_1.getRange)((_b = (_a = error.locations) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : { column: 0, line: 0 }, document); return [ { severity: graphql_language_service_1.DIAGNOSTIC_SEVERITY.Error, message: error.message, source: 'GraphQL: Syntax', range, }, ]; } throw error; } let source = document; const fragmentDefinitions = await this._graphQLCache.getFragmentDefinitions(projectConfig); const fragmentDependencies = await this._graphQLCache.getFragmentDependencies(document, fragmentDefinitions); const dependenciesSource = fragmentDependencies.reduce((prev, cur) => `${prev} ${(0, graphql_1.print)(cur.definition)}`, ''); source = `${source} ${dependenciesSource}`; let validationAst = null; try { validationAst = (0, graphql_1.parse)(source); } catch (_c) { return []; } let customRules = null; if ((extensions === null || extensions === void 0 ? void 0 : extensions.customValidationRules) && typeof extensions.customValidationRules === 'function') { customRules = extensions.customValidationRules(this._graphQLConfig); } const schema = await this._graphQLCache.getSchema(projectName, documentHasExtensions); if (!schema) { return []; } return (0, graphql_language_service_1.validateQuery)(validationAst, schema, customRules, isRelayCompatMode); } async getAutocompleteSuggestions(query, position, filePath) { var _a, _b, _c; const projectConfig = this.getConfigForURI(filePath); if (!projectConfig) { return []; } const schema = await this._graphQLCache.getSchema(projectConfig.name); if (!schema) { return []; } let fragmentInfo = []; try { const fragmentDefinitions = await this._graphQLCache.getFragmentDefinitions(projectConfig); fragmentInfo = Array.from(fragmentDefinitions).map(([, info]) => info.definition); } catch (_d) { } return (0, graphql_language_service_1.getAutocompleteSuggestions)(schema, query, position, undefined, fragmentInfo, { uri: filePath, fillLeafsOnComplete: (_c = (_b = (_a = projectConfig === null || projectConfig === void 0 ? void 0 : projectConfig.extensions) === null || _a === void 0 ? void 0 : _a.languageService) === null || _b === void 0 ? void 0 : _b.fillLeafsOnComplete) !== null && _c !== void 0 ? _c : false, }); } async getHoverInformation(query, position, filePath, options) { const projectConfig = this.getConfigForURI(filePath); if (!projectConfig) { return ''; } const schema = await this._graphQLCache.getSchema(projectConfig.name); if (schema) { return (0, graphql_language_service_1.getHoverInformation)(schema, query, position, undefined, options); } return ''; } async getDefinition(query, position, filePath) { const projectConfig = this.getConfigForURI(filePath); if (!projectConfig) { return null; } const schema = await this._graphQLCache.getSchema(projectConfig.name); if (!schema) { return null; } let ast; try { ast = (0, graphql_1.parse)(query); } catch (_a) { return null; } const node = (0, graphql_language_service_1.getASTNodeAtPosition)(query, ast, position); const type = node && (0, graphql_1.typeFromAST)(schema, node); let queryResult = null; if (node) { switch (node.kind) { case graphql_1.Kind.FRAGMENT_SPREAD: queryResult = await this._getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig); break; case graphql_1.Kind.FRAGMENT_DEFINITION: case graphql_1.Kind.OPERATION_DEFINITION: queryResult = (0, graphql_language_service_1.getDefinitionQueryResultForDefinitionNode)(filePath, query, node); break; case graphql_1.Kind.NAMED_TYPE: queryResult = await this._getDefinitionForNamedType(query, ast, node, filePath, projectConfig); break; case graphql_1.Kind.FIELD: queryResult = await this._getDefinitionForField(query, ast, node, filePath, projectConfig, position); break; case graphql_1.Kind.ARGUMENT: queryResult = await this._getDefinitionForArgument(query, ast, node, filePath, projectConfig, position); break; } } if (queryResult) { return { ...queryResult, node, type, }; } return null; } async getDocumentSymbols(document, filePath) { var _a; const outline = await this.getOutline(document); if (!outline) { return []; } const output = []; const input = outline.outlineTrees.map((tree) => [null, tree]); while (input.length > 0) { const res = input.pop(); if (!res) { return []; } const [parent, tree] = res; if (!tree) { return []; } output.push({ name: (_a = tree.representativeName) !== null && _a !== void 0 ? _a : 'Anonymous', kind: getKind(tree), location: { uri: filePath, range: { start: tree.startPosition, end: tree.endPosition, }, }, containerName: parent ? parent.representativeName : undefined, }); input.push(...tree.children.map(child => [tree, child])); } return output; } async _getDefinitionForNamedType(query, ast, node, filePath, projectConfig) { const objectTypeDefinitions = await this._graphQLCache.getObjectTypeDefinitions(projectConfig); const dependencies = await this._graphQLCache.getObjectTypeDependenciesForAST(ast, objectTypeDefinitions); const localOperationDefinitionInfos = ast.definitions .filter(graphql_1.isTypeDefinitionNode) .map((definition) => ({ filePath, content: query, definition, })); return (0, graphql_language_service_1.getDefinitionQueryResultForNamedType)(query, node, dependencies.concat(localOperationDefinitionInfos)); } async _getDefinitionForField(query, _ast, _node, _filePath, projectConfig, position) { var _a; const token = (0, graphql_language_service_1.getTokenAtPosition)(query, position); const schema = await this._graphQLCache.getSchema(projectConfig.name); const typeInfo = (0, graphql_language_service_1.getTypeInfo)(schema, token.state); const fieldName = (_a = typeInfo.fieldDef) === null || _a === void 0 ? void 0 : _a.name; if (typeInfo && fieldName) { const parentTypeName = typeInfo.parentType.toString(); const objectTypeDefinitions = await this._graphQLCache.getObjectTypeDefinitions(projectConfig); const dependencies = [...objectTypeDefinitions.values()]; return (0, graphql_language_service_1.getDefinitionQueryResultForField)(fieldName, parentTypeName, dependencies); } return null; } async _getDefinitionForArgument(query, _ast, _node, _filePath, projectConfig, position) { var _a, _b, _c, _d; const token = (0, graphql_language_service_1.getTokenAtPosition)(query, position); const schema = await this._graphQLCache.getSchema(projectConfig.name); const typeInfo = (0, graphql_language_service_1.getTypeInfo)(schema, token.state); const fieldName = (_a = typeInfo.fieldDef) === null || _a === void 0 ? void 0 : _a.name; const argumentName = (_b = typeInfo.argDef) === null || _b === void 0 ? void 0 : _b.name; if (typeInfo && fieldName && argumentName) { const objectTypeDefinitions = await this._graphQLCache.getObjectTypeDefinitions(projectConfig); const dependencies = [...objectTypeDefinitions.values()]; return (0, graphql_language_service_1.getDefinitionQueryResultForArgument)(argumentName, fieldName, (_d = (_c = typeInfo.argDef) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.name, dependencies); } return null; } async _getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig) { const fragmentDefinitions = await this._graphQLCache.getFragmentDefinitions(projectConfig); const dependencies = await this._graphQLCache.getFragmentDependenciesForAST(ast, fragmentDefinitions); const localFragDefinitions = ast.definitions.filter(definition => definition.kind === graphql_1.Kind.FRAGMENT_DEFINITION); const typeCastedDefs = localFragDefinitions; const localFragInfos = typeCastedDefs.map((definition) => ({ filePath, content: query, definition, })); return (0, graphql_language_service_1.getDefinitionQueryResultForFragmentSpread)(query, node, dependencies.concat(localFragInfos)); } async getOutline(documentText) { return (0, graphql_language_service_1.getOutline)(documentText); } } exports.GraphQLLanguageService = GraphQLLanguageService; //# sourceMappingURL=GraphQLLanguageService.js.map