@prisma-next/language-server 0.14.0-dev.21 → 0.14.0-dev.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/server.ts CHANGED
@@ -11,7 +11,9 @@ import {
11
11
  type FoldingRange,
12
12
  type InitializeParams,
13
13
  type InitializeResult,
14
+ type Range,
14
15
  RegistrationRequest,
16
+ type SemanticTokens,
15
17
  TextDocumentSyncKind,
16
18
  TextDocuments,
17
19
  type TextEdit,
@@ -27,6 +29,7 @@ import {
27
29
  type ProjectArtifacts,
28
30
  } from './project-artifacts';
29
31
  import type { SchemaInputSet } from './schema-inputs';
32
+ import { buildSemanticTokens, semanticTokensLegend } from './semantic-tokens';
30
33
 
31
34
  export interface LanguageServer {
32
35
  dispose(): void;
@@ -50,6 +53,8 @@ interface ProjectState {
50
53
  readonly artifacts: ProjectArtifacts;
51
54
  }
52
55
 
56
+ const semanticTokenSourceLimit = 100_000;
57
+
53
58
  export function createServer(connection: Connection): LanguageServer {
54
59
  const documents = new TextDocuments(TextDocument);
55
60
  const projects = new Map<string, ProjectState>();
@@ -59,20 +64,22 @@ export function createServer(connection: Connection): LanguageServer {
59
64
  let watchedConfigGlob = join(rootPath, '**', CONFIG_FILENAME);
60
65
  let supportsWatchedFilesRegistration = false;
61
66
 
62
- async function publish(uri: string, text: string): Promise<void> {
67
+ async function publish(uri: string): Promise<void> {
63
68
  const project = await resolveProjectForDocument(uri);
64
69
  if (project === undefined) {
65
70
  return;
66
71
  }
67
- const currentDocument = documents.get(uri);
68
- if (currentDocument === undefined) {
72
+ const document = documents.get(uri);
73
+ if (document === undefined) {
69
74
  documentConfigPaths.delete(uri);
70
75
  return;
71
76
  }
72
- if (currentDocument.getText() !== text) {
73
- return;
74
- }
75
- const computed = project.artifacts.update(uri, text, project.inputs, project.controlStack);
77
+ const computed = project.artifacts.update(
78
+ uri,
79
+ document.getText(),
80
+ project.inputs,
81
+ project.controlStack,
82
+ );
76
83
  if (computed === null) {
77
84
  void connection.sendDiagnostics({ uri, diagnostics: [] });
78
85
  return;
@@ -90,7 +97,11 @@ export function createServer(connection: Connection): LanguageServer {
90
97
  async function resolveProjectForDocument(uri: string): Promise<ProjectState | undefined> {
91
98
  const knownConfigPath = documentConfigPaths.get(uri);
92
99
  if (knownConfigPath !== undefined) {
93
- return resolveProject(knownConfigPath);
100
+ const project = await resolveProjectIfLoadable(knownConfigPath);
101
+ if (project === undefined) {
102
+ documentConfigPaths.delete(uri);
103
+ }
104
+ return project;
94
105
  }
95
106
 
96
107
  const filePath = filePathFromUri(uri);
@@ -190,7 +201,7 @@ export function createServer(connection: Connection): LanguageServer {
190
201
  for (const document of documents.all()) {
191
202
  const knownConfigPath = documentConfigPaths.get(document.uri);
192
203
  if (knownConfigPath === configPath) {
193
- await publish(document.uri, document.getText());
204
+ await publish(document.uri);
194
205
  continue;
195
206
  }
196
207
 
@@ -201,13 +212,13 @@ export function createServer(connection: Connection): LanguageServer {
201
212
  const nearestConfigPath = await findNearestConfigPathForFile(filePath);
202
213
  if (nearestConfigPath === configPath) {
203
214
  documentConfigPaths.set(document.uri, configPath);
204
- await publish(document.uri, document.getText());
215
+ await publish(document.uri);
205
216
  }
206
217
  }
207
218
  }
208
219
 
209
- function publishSafely(uri: string, text: string): void {
210
- void publish(uri, text).catch((error: unknown) => {
220
+ function publishSafely(uri: string): void {
221
+ void publish(uri).catch((error: unknown) => {
211
222
  connection.console.error(error instanceof Error ? error.message : String(error));
212
223
  });
213
224
  }
@@ -248,6 +259,35 @@ export function createServer(connection: Connection): LanguageServer {
248
259
  ];
249
260
  }
250
261
 
262
+ async function semanticTokensForDocument(uri: string, range?: Range): Promise<SemanticTokens> {
263
+ const document = documents.get(uri);
264
+ if (document === undefined) {
265
+ return emptySemanticTokens();
266
+ }
267
+ const text = document.getText();
268
+ if (text.length > semanticTokenSourceLimit) {
269
+ return emptySemanticTokens();
270
+ }
271
+
272
+ const project = await resolveProjectForDocument(uri);
273
+ if (project === undefined) {
274
+ return emptySemanticTokens();
275
+ }
276
+
277
+ const cached = project.artifacts.getDocument(uri);
278
+ if (cached === undefined || cached.text !== text) {
279
+ return emptySemanticTokens();
280
+ }
281
+
282
+ const source = {
283
+ document: cached.document,
284
+ sourceFile: cached.sourceFile,
285
+ symbolTable: project.artifacts.getSymbolTable(),
286
+ scalarTypes: project.controlStack.scalarTypes,
287
+ };
288
+ return buildSemanticTokens(source, range);
289
+ }
290
+
251
291
  connection.onInitialize(async (params): Promise<InitializeResult> => {
252
292
  rootPath = resolveRootPath(params.rootUri, params.rootPath);
253
293
  watchedConfigGlob = join(rootPath, '**', CONFIG_FILENAME);
@@ -258,6 +298,11 @@ export function createServer(connection: Connection): LanguageServer {
258
298
  textDocumentSync: TextDocumentSyncKind.Incremental,
259
299
  documentFormattingProvider: true,
260
300
  foldingRangeProvider: true,
301
+ semanticTokensProvider: {
302
+ legend: semanticTokensLegend,
303
+ full: true,
304
+ range: true,
305
+ },
261
306
  },
262
307
  };
263
308
  });
@@ -299,6 +344,13 @@ export function createServer(connection: Connection): LanguageServer {
299
344
 
300
345
  connection.onDocumentFormatting((params) => formatDocument(params.textDocument.uri));
301
346
 
347
+ connection.languages.semanticTokens.on((params) =>
348
+ semanticTokensForDocument(params.textDocument.uri),
349
+ );
350
+ connection.languages.semanticTokens.onRange((params) =>
351
+ semanticTokensForDocument(params.textDocument.uri, params.range),
352
+ );
353
+
302
354
  connection.onFoldingRanges(async (params): Promise<FoldingRange[]> => {
303
355
  let project: ProjectState | undefined;
304
356
  try {
@@ -317,10 +369,10 @@ export function createServer(connection: Connection): LanguageServer {
317
369
  });
318
370
 
319
371
  documents.onDidOpen((event) => {
320
- publishSafely(event.document.uri, event.document.getText());
372
+ publishSafely(event.document.uri);
321
373
  });
322
374
  documents.onDidChangeContent((event) => {
323
- publishSafely(event.document.uri, event.document.getText());
375
+ publishSafely(event.document.uri);
324
376
  });
325
377
  documents.onDidClose((event) => {
326
378
  const uri = event.document.uri;
@@ -349,6 +401,10 @@ export function createServer(connection: Connection): LanguageServer {
349
401
  };
350
402
  }
351
403
 
404
+ function emptySemanticTokens(): SemanticTokens {
405
+ return { data: [] };
406
+ }
407
+
352
408
  function toLspSeverity(severity: number): DiagnosticSeverity {
353
409
  switch (severity) {
354
410
  case ParseDiagnosticSeverity.Warning: