UNPKG

apollo-language-server

Version:

A language server for Apollo GraphQL projects

221 lines 7.79 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GraphQLProject = void 0; const path_1 = require("path"); const fs_1 = require("fs"); const vscode_uri_1 = __importDefault(require("vscode-uri")); const graphql_1 = require("graphql"); const vscode_languageserver_1 = require("vscode-languageserver"); const document_1 = require("../document"); const config_1 = require("../config"); const schema_1 = require("../providers/schema"); const engine_1 = require("../engine"); const fileAssociations = { ".graphql": "graphql", ".gql": "graphql", ".js": "javascript", ".ts": "typescript", ".jsx": "javascriptreact", ".tsx": "typescriptreact", ".vue": "vue", ".py": "python", ".rb": "ruby", ".dart": "dart", ".re": "reason", ".ex": "elixir", ".exs": "elixir", }; class GraphQLProject { constructor({ config, fileSet, loadingHandler, clientIdentity, }) { this.needsValidation = false; this.documentsByFile = new Map(); this.config = config; this.fileSet = fileSet; this.loadingHandler = loadingHandler; this.schemaProvider = (0, schema_1.schemaProviderFromConfig)(config, clientIdentity); const { engine } = config; if (engine.apiKey) { this.engineClient = new engine_1.ApolloEngineClient(engine.apiKey, engine.endpoint, clientIdentity); } this._isReady = false; this.readyPromise = Promise.all(this.initialize()) .then(() => { this._isReady = true; }) .catch((error) => { console.error(error); this.loadingHandler.showError(`Error initializing Apollo GraphQL project "${this.displayName}": ${error}`); }); } get isReady() { return this._isReady; } get engine() { if (!this.engineClient) { throw new Error(`Unable to find ${config_1.keyEnvVar}`); } return this.engineClient; } get whenReady() { return this.readyPromise; } updateConfig(config) { this.config = config; return this.initialize(); } resolveSchema(config) { this.lastLoadDate = +new Date(); return this.schemaProvider.resolveSchema(config); } resolveFederatedServiceSDL() { return this.schemaProvider.resolveFederatedServiceSDL(); } onSchemaChange(handler) { this.lastLoadDate = +new Date(); return this.schemaProvider.onSchemaChange(handler); } onDiagnostics(handler) { this._onDiagnostics = handler; } includesFile(uri) { return this.fileSet.includesFile(uri); } async scanAllIncludedFiles() { await this.loadingHandler.handle(`Loading queries for ${this.displayName}`, (async () => { for (const filePath of this.fileSet.allFiles()) { const uri = vscode_uri_1.default.file(filePath).toString(); if (this.documentsByFile.has(uri)) continue; this.fileDidChange(uri); } })()); } fileDidChange(uri) { const filePath = vscode_uri_1.default.parse(uri).fsPath; const extension = (0, path_1.extname)(filePath); const languageId = fileAssociations[extension]; if (!languageId) return; if (!(0, fs_1.lstatSync)(filePath).isFile()) return; const contents = (0, fs_1.readFileSync)(filePath, "utf8"); const document = vscode_languageserver_1.TextDocument.create(uri, languageId, -1, contents); this.documentDidChange(document); } fileWasDeleted(uri) { this.removeGraphQLDocumentsFor(uri); this.checkForDuplicateOperations(); } documentDidChange(document) { const documents = (0, document_1.extractGraphQLDocuments)(document, this.config.client && this.config.client.tagName); if (documents) { this.documentsByFile.set(document.uri, documents); this.invalidate(); } else { this.removeGraphQLDocumentsFor(document.uri); } this.checkForDuplicateOperations(); } checkForDuplicateOperations() { const operations = Object.create(null); for (const document of this.documents) { if (!document.ast) continue; for (const definition of document.ast.definitions) { if (definition.kind === graphql_1.Kind.OPERATION_DEFINITION && definition.name) { if (operations[definition.name.value]) { throw new Error(`️️There are multiple definitions for the \`${definition.name.value}\` operation. Please rename or remove all operations with the duplicated name before continuing.`); } operations[definition.name.value] = definition; } } } } removeGraphQLDocumentsFor(uri) { if (this.documentsByFile.has(uri)) { this.documentsByFile.delete(uri); if (this._onDiagnostics) { this._onDiagnostics({ uri: uri, diagnostics: [] }); } this.invalidate(); } } invalidate() { if (!this.needsValidation && this.isReady) { setTimeout(() => { this.validateIfNeeded(); }, 0); this.needsValidation = true; } } validateIfNeeded() { if (!this.needsValidation || !this.isReady) return; this.validate(); this.needsValidation = false; } clearAllDiagnostics() { if (!this._onDiagnostics) return; for (const uri of this.documentsByFile.keys()) { this._onDiagnostics({ uri, diagnostics: [] }); } } documentsAt(uri) { return this.documentsByFile.get(uri); } documentAt(uri, position) { const queryDocuments = this.documentsByFile.get(uri); if (!queryDocuments) return undefined; return queryDocuments.find((document) => document.containsPosition(position)); } get documents() { const documents = []; for (const documentsForFile of this.documentsByFile.values()) { documents.push(...documentsForFile); } return documents; } get definitions() { const definitions = []; for (const document of this.documents) { if (!document.ast) continue; definitions.push(...document.ast.definitions); } return definitions; } definitionsAt(uri) { const documents = this.documentsAt(uri); if (!documents) return []; const definitions = []; for (const document of documents) { if (!document.ast) continue; definitions.push(...document.ast.definitions); } return definitions; } get typeSystemDefinitionsAndExtensions() { const definitionsAndExtensions = []; for (const document of this.documents) { if (!document.ast) continue; for (const definition of document.ast.definitions) { if ((0, graphql_1.isTypeSystemDefinitionNode)(definition) || (0, graphql_1.isTypeSystemExtensionNode)(definition)) { definitionsAndExtensions.push(definition); } } } return definitionsAndExtensions; } } exports.GraphQLProject = GraphQLProject; //# sourceMappingURL=base.js.map