UNPKG

graphql-language-service-interface

Version:
246 lines 12.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GraphQLLanguageService = void 0; const vscode_languageserver_types_1 = require("vscode-languageserver-types"); const graphql_1 = require("graphql"); const getAutocompleteSuggestions_1 = require("./getAutocompleteSuggestions"); const getHoverInformation_1 = require("./getHoverInformation"); const getDiagnostics_1 = require("./getDiagnostics"); const getDefinition_1 = require("./getDefinition"); const getOutline_1 = require("./getOutline"); const graphql_language_service_utils_1 = require("graphql-language-service-utils"); const { FRAGMENT_DEFINITION, OBJECT_TYPE_DEFINITION, INTERFACE_TYPE_DEFINITION, ENUM_TYPE_DEFINITION, UNION_TYPE_DEFINITION, SCALAR_TYPE_DEFINITION, INPUT_OBJECT_TYPE_DEFINITION, SCALAR_TYPE_EXTENSION, OBJECT_TYPE_EXTENSION, INTERFACE_TYPE_EXTENSION, UNION_TYPE_EXTENSION, ENUM_TYPE_EXTENSION, INPUT_OBJECT_TYPE_EXTENSION, DIRECTIVE_DEFINITION, FRAGMENT_SPREAD, OPERATION_DEFINITION, NAMED_TYPE, } = graphql_1.Kind; 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) { this._graphQLCache = cache; this._graphQLConfig = cache.getGraphQLConfig(); } getConfigForURI(uri) { const config = this._graphQLCache.getProjectForFile(uri); if (config) { return config; } throw Error(`No config found for uri: ${uri}`); } getDiagnostics(query, uri, isRelayCompatMode) { return __awaiter(this, void 0, void 0, function* () { let queryHasExtensions = false; const projectConfig = this.getConfigForURI(uri); if (!projectConfig) { return []; } const { schema: schemaPath, name: projectName, extensions } = projectConfig; try { const queryAST = graphql_1.parse(query); if (!schemaPath || uri !== schemaPath) { queryHasExtensions = queryAST.definitions.some(definition => { switch (definition.kind) { case OBJECT_TYPE_DEFINITION: case INTERFACE_TYPE_DEFINITION: case ENUM_TYPE_DEFINITION: case UNION_TYPE_DEFINITION: case SCALAR_TYPE_DEFINITION: case INPUT_OBJECT_TYPE_DEFINITION: case SCALAR_TYPE_EXTENSION: case OBJECT_TYPE_EXTENSION: case INTERFACE_TYPE_EXTENSION: case UNION_TYPE_EXTENSION: case ENUM_TYPE_EXTENSION: case INPUT_OBJECT_TYPE_EXTENSION: case DIRECTIVE_DEFINITION: return true; } return false; }); } } catch (error) { const range = getDiagnostics_1.getRange(error.locations[0], query); return [ { severity: getDiagnostics_1.DIAGNOSTIC_SEVERITY.Error, message: error.message, source: 'GraphQL: Syntax', range, }, ]; } let source = query; const fragmentDefinitions = yield this._graphQLCache.getFragmentDefinitions(projectConfig); const fragmentDependencies = yield this._graphQLCache.getFragmentDependencies(query, fragmentDefinitions); const dependenciesSource = fragmentDependencies.reduce((prev, cur) => `${prev} ${graphql_1.print(cur.definition)}`, ''); source = `${source} ${dependenciesSource}`; let validationAst = null; try { validationAst = graphql_1.parse(source); } catch (error) { 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 = yield this._graphQLCache.getSchema(projectName, queryHasExtensions); if (!schema) { return []; } return getDiagnostics_1.validateQuery(validationAst, schema, customRules, isRelayCompatMode); }); } getAutocompleteSuggestions(query, position, filePath) { return __awaiter(this, void 0, void 0, function* () { const projectConfig = this.getConfigForURI(filePath); const schema = yield this._graphQLCache.getSchema(projectConfig.name); const fragmentDefinitions = yield this._graphQLCache.getFragmentDefinitions(projectConfig); const fragmentInfo = Array.from(fragmentDefinitions).map(([, info]) => info.definition); if (schema) { return getAutocompleteSuggestions_1.getAutocompleteSuggestions(schema, query, position, undefined, fragmentInfo); } return []; }); } getHoverInformation(query, position, filePath) { return __awaiter(this, void 0, void 0, function* () { const projectConfig = this.getConfigForURI(filePath); const schema = yield this._graphQLCache.getSchema(projectConfig.name); if (schema) { return getHoverInformation_1.getHoverInformation(schema, query, position); } return ''; }); } getDefinition(query, position, filePath) { return __awaiter(this, void 0, void 0, function* () { const projectConfig = this.getConfigForURI(filePath); let ast; try { ast = graphql_1.parse(query); } catch (error) { return null; } const node = graphql_language_service_utils_1.getASTNodeAtPosition(query, ast, position); if (node) { switch (node.kind) { case FRAGMENT_SPREAD: return this._getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig); case FRAGMENT_DEFINITION: case OPERATION_DEFINITION: return getDefinition_1.getDefinitionQueryResultForDefinitionNode(filePath, query, node); case NAMED_TYPE: return this._getDefinitionForNamedType(query, ast, node, filePath, projectConfig); } } return null; }); } getDocumentSymbols(document, filePath) { return __awaiter(this, void 0, void 0, function* () { const outline = yield 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: tree.representativeName, 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; }); } _getDefinitionForNamedType(query, ast, node, filePath, projectConfig) { return __awaiter(this, void 0, void 0, function* () { const objectTypeDefinitions = yield this._graphQLCache.getObjectTypeDefinitions(projectConfig); const dependencies = yield this._graphQLCache.getObjectTypeDependenciesForAST(ast, objectTypeDefinitions); const localObjectTypeDefinitions = ast.definitions.filter(definition => definition.kind === OBJECT_TYPE_DEFINITION || definition.kind === INPUT_OBJECT_TYPE_DEFINITION || definition.kind === ENUM_TYPE_DEFINITION || definition.kind === SCALAR_TYPE_DEFINITION || definition.kind === INTERFACE_TYPE_DEFINITION); const typeCastedDefs = localObjectTypeDefinitions; const localOperationDefinationInfos = typeCastedDefs.map((definition) => ({ filePath, content: query, definition, })); const result = yield getDefinition_1.getDefinitionQueryResultForNamedType(query, node, dependencies.concat(localOperationDefinationInfos)); return result; }); } _getDefinitionForFragmentSpread(query, ast, node, filePath, projectConfig) { return __awaiter(this, void 0, void 0, function* () { const fragmentDefinitions = yield this._graphQLCache.getFragmentDefinitions(projectConfig); const dependencies = yield this._graphQLCache.getFragmentDependenciesForAST(ast, fragmentDefinitions); const localFragDefinitions = ast.definitions.filter(definition => definition.kind === FRAGMENT_DEFINITION); const typeCastedDefs = localFragDefinitions; const localFragInfos = typeCastedDefs.map((definition) => ({ filePath, content: query, definition, })); const result = yield getDefinition_1.getDefinitionQueryResultForFragmentSpread(query, node, dependencies.concat(localFragInfos)); return result; }); } getOutline(documentText) { return __awaiter(this, void 0, void 0, function* () { return getOutline_1.getOutline(documentText); }); } } exports.GraphQLLanguageService = GraphQLLanguageService; //# sourceMappingURL=GraphQLLanguageService.js.map