1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | exports.GraphQLProject = void 0;
|
7 | const path_1 = require("path");
|
8 | const fs_1 = require("fs");
|
9 | const vscode_uri_1 = __importDefault(require("vscode-uri"));
|
10 | const graphql_1 = require("graphql");
|
11 | const vscode_languageserver_1 = require("vscode-languageserver");
|
12 | const document_1 = require("../document");
|
13 | const config_1 = require("../config");
|
14 | const schema_1 = require("../providers/schema");
|
15 | const engine_1 = require("../engine");
|
16 | const fileAssociations = {
|
17 | ".graphql": "graphql",
|
18 | ".gql": "graphql",
|
19 | ".js": "javascript",
|
20 | ".ts": "typescript",
|
21 | ".jsx": "javascriptreact",
|
22 | ".tsx": "typescriptreact",
|
23 | ".vue": "vue",
|
24 | ".py": "python",
|
25 | ".rb": "ruby",
|
26 | ".dart": "dart",
|
27 | ".re": "reason",
|
28 | ".ex": "elixir",
|
29 | ".exs": "elixir"
|
30 | };
|
31 | class GraphQLProject {
|
32 | constructor({ config, fileSet, loadingHandler, clientIdentity }) {
|
33 | this.needsValidation = false;
|
34 | this.documentsByFile = new Map();
|
35 | this.config = config;
|
36 | this.fileSet = fileSet;
|
37 | this.loadingHandler = loadingHandler;
|
38 | this.schemaProvider = schema_1.schemaProviderFromConfig(config, clientIdentity);
|
39 | const { engine } = config;
|
40 | if (engine.apiKey) {
|
41 | this.engineClient = new engine_1.ApolloEngineClient(engine.apiKey, engine.endpoint, clientIdentity);
|
42 | }
|
43 | this._isReady = false;
|
44 | this.readyPromise = Promise.all(this.initialize())
|
45 | .then(() => {
|
46 | this._isReady = true;
|
47 | })
|
48 | .catch(error => {
|
49 | console.error(error);
|
50 | this.loadingHandler.showError(`Error initializing Apollo GraphQL project "${this.displayName}": ${error}`);
|
51 | });
|
52 | }
|
53 | get isReady() {
|
54 | return this._isReady;
|
55 | }
|
56 | get engine() {
|
57 | if (!this.engineClient) {
|
58 | throw new Error(`Unable to find ${config_1.keyEnvVar}`);
|
59 | }
|
60 | return this.engineClient;
|
61 | }
|
62 | get whenReady() {
|
63 | return this.readyPromise;
|
64 | }
|
65 | updateConfig(config) {
|
66 | this.config = config;
|
67 | return this.initialize();
|
68 | }
|
69 | resolveSchema(config) {
|
70 | this.lastLoadDate = +new Date();
|
71 | return this.schemaProvider.resolveSchema(config);
|
72 | }
|
73 | resolveFederatedServiceSDL() {
|
74 | return this.schemaProvider.resolveFederatedServiceSDL();
|
75 | }
|
76 | onSchemaChange(handler) {
|
77 | this.lastLoadDate = +new Date();
|
78 | return this.schemaProvider.onSchemaChange(handler);
|
79 | }
|
80 | onDiagnostics(handler) {
|
81 | this._onDiagnostics = handler;
|
82 | }
|
83 | includesFile(uri) {
|
84 | return this.fileSet.includesFile(uri);
|
85 | }
|
86 | async scanAllIncludedFiles() {
|
87 | await this.loadingHandler.handle(`Loading queries for ${this.displayName}`, (async () => {
|
88 | for (const filePath of this.fileSet.allFiles()) {
|
89 | const uri = vscode_uri_1.default.file(filePath).toString();
|
90 | if (this.documentsByFile.has(uri))
|
91 | continue;
|
92 | this.fileDidChange(uri);
|
93 | }
|
94 | })());
|
95 | }
|
96 | fileDidChange(uri) {
|
97 | const filePath = vscode_uri_1.default.parse(uri).fsPath;
|
98 | const extension = path_1.extname(filePath);
|
99 | const languageId = fileAssociations[extension];
|
100 | if (!languageId)
|
101 | return;
|
102 | if (!fs_1.lstatSync(filePath).isFile())
|
103 | return;
|
104 | const contents = fs_1.readFileSync(filePath, "utf8");
|
105 | const document = vscode_languageserver_1.TextDocument.create(uri, languageId, -1, contents);
|
106 | this.documentDidChange(document);
|
107 | }
|
108 | fileWasDeleted(uri) {
|
109 | this.removeGraphQLDocumentsFor(uri);
|
110 | this.checkForDuplicateOperations();
|
111 | }
|
112 | documentDidChange(document) {
|
113 | const documents = document_1.extractGraphQLDocuments(document, this.config.client && this.config.client.tagName);
|
114 | if (documents) {
|
115 | this.documentsByFile.set(document.uri, documents);
|
116 | this.invalidate();
|
117 | }
|
118 | else {
|
119 | this.removeGraphQLDocumentsFor(document.uri);
|
120 | }
|
121 | this.checkForDuplicateOperations();
|
122 | }
|
123 | checkForDuplicateOperations() {
|
124 | const operations = Object.create(null);
|
125 | for (const document of this.documents) {
|
126 | if (!document.ast)
|
127 | continue;
|
128 | for (const definition of document.ast.definitions) {
|
129 | if (definition.kind === graphql_1.Kind.OPERATION_DEFINITION && definition.name) {
|
130 | if (operations[definition.name.value]) {
|
131 | 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.`);
|
132 | }
|
133 | operations[definition.name.value] = definition;
|
134 | }
|
135 | }
|
136 | }
|
137 | }
|
138 | removeGraphQLDocumentsFor(uri) {
|
139 | if (this.documentsByFile.has(uri)) {
|
140 | this.documentsByFile.delete(uri);
|
141 | if (this._onDiagnostics) {
|
142 | this._onDiagnostics({ uri: uri, diagnostics: [] });
|
143 | }
|
144 | this.invalidate();
|
145 | }
|
146 | }
|
147 | invalidate() {
|
148 | if (!this.needsValidation && this.isReady) {
|
149 | setTimeout(() => {
|
150 | this.validateIfNeeded();
|
151 | }, 0);
|
152 | this.needsValidation = true;
|
153 | }
|
154 | }
|
155 | validateIfNeeded() {
|
156 | if (!this.needsValidation || !this.isReady)
|
157 | return;
|
158 | this.validate();
|
159 | this.needsValidation = false;
|
160 | }
|
161 | clearAllDiagnostics() {
|
162 | if (!this._onDiagnostics)
|
163 | return;
|
164 | for (const uri of this.documentsByFile.keys()) {
|
165 | this._onDiagnostics({ uri, diagnostics: [] });
|
166 | }
|
167 | }
|
168 | documentsAt(uri) {
|
169 | return this.documentsByFile.get(uri);
|
170 | }
|
171 | documentAt(uri, position) {
|
172 | const queryDocuments = this.documentsByFile.get(uri);
|
173 | if (!queryDocuments)
|
174 | return undefined;
|
175 | return queryDocuments.find(document => document.containsPosition(position));
|
176 | }
|
177 | get documents() {
|
178 | const documents = [];
|
179 | for (const documentsForFile of this.documentsByFile.values()) {
|
180 | documents.push(...documentsForFile);
|
181 | }
|
182 | return documents;
|
183 | }
|
184 | get definitions() {
|
185 | const definitions = [];
|
186 | for (const document of this.documents) {
|
187 | if (!document.ast)
|
188 | continue;
|
189 | definitions.push(...document.ast.definitions);
|
190 | }
|
191 | return definitions;
|
192 | }
|
193 | definitionsAt(uri) {
|
194 | const documents = this.documentsAt(uri);
|
195 | if (!documents)
|
196 | return [];
|
197 | const definitions = [];
|
198 | for (const document of documents) {
|
199 | if (!document.ast)
|
200 | continue;
|
201 | definitions.push(...document.ast.definitions);
|
202 | }
|
203 | return definitions;
|
204 | }
|
205 | get typeSystemDefinitionsAndExtensions() {
|
206 | const definitionsAndExtensions = [];
|
207 | for (const document of this.documents) {
|
208 | if (!document.ast)
|
209 | continue;
|
210 | for (const definition of document.ast.definitions) {
|
211 | if (graphql_1.isTypeSystemDefinitionNode(definition) ||
|
212 | graphql_1.isTypeSystemExtensionNode(definition)) {
|
213 | definitionsAndExtensions.push(definition);
|
214 | }
|
215 | }
|
216 | }
|
217 | return definitionsAndExtensions;
|
218 | }
|
219 | }
|
220 | exports.GraphQLProject = GraphQLProject;
|
221 |
|
\ | No newline at end of file |