@prisma-next/language-server 0.14.0-dev.47 → 0.14.0-dev.48
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/README.md +8 -8
- package/dist/exports/index.d.mts +3 -3
- package/dist/exports/index.d.mts.map +1 -1
- package/dist/exports/index.mjs +211 -133
- package/dist/exports/index.mjs.map +1 -1
- package/package.json +10 -9
- package/src/completion-provider.ts +4 -12
- package/src/project-artifacts.ts +86 -39
- package/src/schema-inputs.ts +3 -0
- package/src/semantic-tokens.ts +18 -20
- package/src/server.ts +268 -126
package/dist/exports/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { join } from "node:path";
|
|
2
1
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
3
2
|
import { findNearestConfigPathForFile, loadConfig } from "@prisma-next/config-loader";
|
|
4
3
|
import { format } from "@prisma-next/psl-parser/format";
|
|
5
|
-
import {
|
|
4
|
+
import { join } from "pathe";
|
|
5
|
+
import { CompletionItemKind, DiagnosticSeverity, DidChangeWatchedFilesNotification, DocumentDiagnosticReportKind, FoldingRangeKind, InsertTextFormat, RegistrationRequest, SemanticTokenModifiers, SemanticTokenTypes, TextDocumentSyncKind, TextDocuments } from "vscode-languageserver";
|
|
6
6
|
import { TextDocument } from "vscode-languageserver-textdocument";
|
|
7
7
|
import { ArrayLiteralAst, AttributeArgListAst, BooleanLiteralExprAst, CompositeTypeDeclarationAst, FieldAttributeAst, FieldDeclarationAst, FunctionCallAst, GenericBlockDeclarationAst, IdentifierAst, KeyValuePairAst, ModelAttributeAst, ModelDeclarationAst, NamespaceDeclarationAst, NumberLiteralExprAst, ObjectLiteralExprAst, StringLiteralExprAst, TypesBlockAst, any, filterChildren, findChildToken, parse, skipTriviaToken } from "@prisma-next/psl-parser/syntax";
|
|
8
8
|
import { isAuthoringPslBlockDescriptor } from "@prisma-next/framework-components/authoring";
|
|
@@ -348,7 +348,7 @@ function provideModelTypeCompletionItems(context, sourceFile, source) {
|
|
|
348
348
|
}
|
|
349
349
|
function provideNamespaceMemberCompletionItems(context, sourceFile, source) {
|
|
350
350
|
if (context.space !== void 0) return [];
|
|
351
|
-
return modelTypeCompletionItems(context, sourceFile, namespaceCandidates(source.symbolTable
|
|
351
|
+
return modelTypeCompletionItems(context, sourceFile, namespaceCandidates(source.symbolTable.topLevel.namespaces[context.namespace]));
|
|
352
352
|
}
|
|
353
353
|
function modelTypeCompletionItems(context, sourceFile, candidates) {
|
|
354
354
|
const replacementRange = {
|
|
@@ -378,7 +378,6 @@ function configuredScalarCandidates(scalarTypes) {
|
|
|
378
378
|
}));
|
|
379
379
|
}
|
|
380
380
|
function topLevelSymbolCandidates(symbolTable) {
|
|
381
|
-
if (symbolTable === void 0) return [];
|
|
382
381
|
const { topLevel } = symbolTable;
|
|
383
382
|
return [
|
|
384
383
|
...symbolCandidates(recordNames(topLevel.models), "topLevelModel", "Model", CompletionItemKind.Class),
|
|
@@ -388,7 +387,6 @@ function topLevelSymbolCandidates(symbolTable) {
|
|
|
388
387
|
];
|
|
389
388
|
}
|
|
390
389
|
function allNamespaceCandidates(symbolTable) {
|
|
391
|
-
if (symbolTable === void 0) return [];
|
|
392
390
|
return Object.values(symbolTable.topLevel.namespaces).sort((left, right) => compareNames(left.name, right.name)).map(namespaceQualifierCandidate);
|
|
393
391
|
}
|
|
394
392
|
function namespaceCandidates(namespace) {
|
|
@@ -441,7 +439,10 @@ function hasPslInputs(config) {
|
|
|
441
439
|
function resolveSchemaInputs(config) {
|
|
442
440
|
const inputs = hasPslInputs(config) ? config.contract?.source.inputs : void 0;
|
|
443
441
|
const uris = new Set(inputs?.map((input) => pathToFileURL(input).toString()));
|
|
444
|
-
return {
|
|
442
|
+
return {
|
|
443
|
+
includes: (uri) => uris.has(uri),
|
|
444
|
+
uris: () => uris
|
|
445
|
+
};
|
|
445
446
|
}
|
|
446
447
|
//#endregion
|
|
447
448
|
//#region src/config-resolution.ts
|
|
@@ -552,29 +553,48 @@ function computeDocumentDiagnostics(uri, text, inputs, controlStack) {
|
|
|
552
553
|
}
|
|
553
554
|
//#endregion
|
|
554
555
|
//#region src/project-artifacts.ts
|
|
555
|
-
function createProjectArtifacts() {
|
|
556
|
+
function createProjectArtifacts(options) {
|
|
557
|
+
const { inputs, controlStack, getText } = options;
|
|
556
558
|
const documents = /* @__PURE__ */ new Map();
|
|
557
559
|
let symbolTable;
|
|
560
|
+
function drop(uri) {
|
|
561
|
+
if (documents.delete(uri)) symbolTable = void 0;
|
|
562
|
+
}
|
|
563
|
+
function readDocument(uri) {
|
|
564
|
+
const existing = documents.get(uri);
|
|
565
|
+
if (existing !== void 0) return existing;
|
|
566
|
+
const text = getText(uri);
|
|
567
|
+
if (text === void 0) return;
|
|
568
|
+
const computed = computeDocumentDiagnostics(uri, text, inputs, controlStack);
|
|
569
|
+
if (computed === null) return;
|
|
570
|
+
const artifacts = {
|
|
571
|
+
document: computed.document,
|
|
572
|
+
sourceFile: computed.sourceFile,
|
|
573
|
+
diagnostics: computed.diagnostics
|
|
574
|
+
};
|
|
575
|
+
documents.set(uri, artifacts);
|
|
576
|
+
symbolTable = computed.symbolTable;
|
|
577
|
+
return artifacts;
|
|
578
|
+
}
|
|
558
579
|
return {
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const
|
|
563
|
-
|
|
564
|
-
if (
|
|
565
|
-
|
|
580
|
+
document: readDocument,
|
|
581
|
+
symbolTable: () => {
|
|
582
|
+
if (symbolTable !== void 0) return symbolTable;
|
|
583
|
+
for (const uri of inputs.uris()) {
|
|
584
|
+
const artifacts = readDocument(uri);
|
|
585
|
+
if (artifacts === void 0) continue;
|
|
586
|
+
symbolTable ??= buildSymbolTable({
|
|
587
|
+
document: artifacts.document,
|
|
588
|
+
sourceFile: artifacts.sourceFile,
|
|
589
|
+
scalarTypes: controlStack.scalarTypes,
|
|
590
|
+
pslBlockDescriptors: controlStack.pslBlockDescriptors
|
|
591
|
+
}).table;
|
|
592
|
+
return symbolTable;
|
|
566
593
|
}
|
|
567
|
-
|
|
568
|
-
document: computed.document,
|
|
569
|
-
sourceFile: computed.sourceFile,
|
|
570
|
-
text
|
|
571
|
-
});
|
|
572
|
-
symbolTable = computed.symbolTable;
|
|
573
|
-
return computed.diagnostics;
|
|
594
|
+
throw new Error("invariant violated: project has no open configured input — the server must drop such projects");
|
|
574
595
|
},
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
}
|
|
596
|
+
documentChanged: drop,
|
|
597
|
+
documentClosed: drop
|
|
578
598
|
};
|
|
579
599
|
}
|
|
580
600
|
//#endregion
|
|
@@ -827,21 +847,19 @@ function classifyTypeReference(path, source, namespace) {
|
|
|
827
847
|
if (name === void 0) return { tokenType: "type" };
|
|
828
848
|
const table = source.symbolTable;
|
|
829
849
|
const namespaceName = path.length > 1 ? path[path.length - 2] : namespace;
|
|
830
|
-
const namespaceScope = namespaceName !== void 0 ? table
|
|
850
|
+
const namespaceScope = namespaceName !== void 0 ? table.topLevel.namespaces[namespaceName] : void 0;
|
|
831
851
|
if (namespaceScope !== void 0) {
|
|
832
852
|
if (Object.hasOwn(namespaceScope.models, name)) return { tokenType: "class" };
|
|
833
853
|
if (Object.hasOwn(namespaceScope.compositeTypes, name)) return { tokenType: "struct" };
|
|
834
854
|
if (Object.hasOwn(namespaceScope.blocks, name)) return { tokenType: "type" };
|
|
835
855
|
}
|
|
836
|
-
if (table
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
if (Object.hasOwn(table.topLevel.typeAliases, name) || Object.hasOwn(table.topLevel.blocks, name)) return { tokenType: "type" };
|
|
844
|
-
}
|
|
856
|
+
if (Object.hasOwn(table.topLevel.models, name)) return { tokenType: "class" };
|
|
857
|
+
if (Object.hasOwn(table.topLevel.compositeTypes, name)) return { tokenType: "struct" };
|
|
858
|
+
if (Object.hasOwn(table.topLevel.scalars, name)) return {
|
|
859
|
+
tokenType: "type",
|
|
860
|
+
modifierBitset: semanticTokenModifierBits.defaultLibrary
|
|
861
|
+
};
|
|
862
|
+
if (Object.hasOwn(table.topLevel.typeAliases, name) || Object.hasOwn(table.topLevel.blocks, name)) return { tokenType: "type" };
|
|
845
863
|
if (source.scalarTypes.includes(name)) return {
|
|
846
864
|
tokenType: "type",
|
|
847
865
|
modifierBitset: semanticTokenModifierBits.defaultLibrary
|
|
@@ -849,7 +867,7 @@ function classifyTypeReference(path, source, namespace) {
|
|
|
849
867
|
return { tokenType: "type" };
|
|
850
868
|
}
|
|
851
869
|
function isKnownNamespace(name, table) {
|
|
852
|
-
return
|
|
870
|
+
return Object.hasOwn(table.topLevel.namespaces, name);
|
|
853
871
|
}
|
|
854
872
|
function identifierSegments(name) {
|
|
855
873
|
const segments = [];
|
|
@@ -917,13 +935,11 @@ function tokenTypeIndex(tokenType) {
|
|
|
917
935
|
const semanticTokenSourceLimit = 1e5;
|
|
918
936
|
function createServer(connection) {
|
|
919
937
|
const documents = new TextDocuments(TextDocument);
|
|
920
|
-
const
|
|
921
|
-
const projectLoads = /* @__PURE__ */ new Map();
|
|
938
|
+
const managedProjects = /* @__PURE__ */ new Map();
|
|
922
939
|
const documentConfigPaths = /* @__PURE__ */ new Map();
|
|
923
940
|
let rootPath = process.cwd();
|
|
924
941
|
let watchedConfigGlob = join(rootPath, "**", CONFIG_FILENAME);
|
|
925
|
-
let
|
|
926
|
-
let clientSupportsSnippets = false;
|
|
942
|
+
let clientCapabilities = noClientCapabilities;
|
|
927
943
|
let disposed = false;
|
|
928
944
|
function sendDiagnostics(params) {
|
|
929
945
|
if (disposed) return;
|
|
@@ -936,13 +952,12 @@ function createServer(connection) {
|
|
|
936
952
|
async function publish(uri) {
|
|
937
953
|
const project = await resolveProjectForDocument(uri);
|
|
938
954
|
if (project === void 0) return;
|
|
939
|
-
|
|
940
|
-
if (document === void 0) {
|
|
955
|
+
if (documents.get(uri) === void 0) {
|
|
941
956
|
documentConfigPaths.delete(uri);
|
|
942
957
|
return;
|
|
943
958
|
}
|
|
944
|
-
const
|
|
945
|
-
if (
|
|
959
|
+
const artifacts = project.artifacts.document(uri);
|
|
960
|
+
if (artifacts === void 0) {
|
|
946
961
|
sendDiagnostics({
|
|
947
962
|
uri,
|
|
948
963
|
diagnostics: []
|
|
@@ -951,16 +966,27 @@ function createServer(connection) {
|
|
|
951
966
|
}
|
|
952
967
|
sendDiagnostics({
|
|
953
968
|
uri,
|
|
954
|
-
diagnostics:
|
|
955
|
-
range: diagnostic.range,
|
|
956
|
-
message: diagnostic.message,
|
|
957
|
-
code: diagnostic.code,
|
|
958
|
-
severity: toLspSeverity(diagnostic.severity),
|
|
959
|
-
source: "prisma-next"
|
|
960
|
-
}))
|
|
969
|
+
diagnostics: toDiagnostics(artifacts.diagnostics)
|
|
961
970
|
});
|
|
962
971
|
}
|
|
972
|
+
/**
|
|
973
|
+
* Project-scoped so a future multi-input symbol table can attach
|
|
974
|
+
* `relatedDocuments` for cross-file effects.
|
|
975
|
+
*/
|
|
976
|
+
function buildDocumentDiagnosticReport(project, uri) {
|
|
977
|
+
const artifacts = project.artifacts.document(uri);
|
|
978
|
+
return {
|
|
979
|
+
kind: DocumentDiagnosticReportKind.Full,
|
|
980
|
+
items: artifacts === void 0 ? [] : toDiagnostics(artifacts.diagnostics)
|
|
981
|
+
};
|
|
982
|
+
}
|
|
963
983
|
async function resolveProjectForDocument(uri) {
|
|
984
|
+
const project = await projectForNearestConfig(uri);
|
|
985
|
+
if (project === void 0 || project.inputs.includes(uri)) return project;
|
|
986
|
+
documentConfigPaths.delete(uri);
|
|
987
|
+
dropProjectWithoutManagedDocuments(project.configPath);
|
|
988
|
+
}
|
|
989
|
+
async function projectForNearestConfig(uri) {
|
|
964
990
|
const knownConfigPath = documentConfigPaths.get(uri);
|
|
965
991
|
if (knownConfigPath !== void 0) {
|
|
966
992
|
const project = await resolveProjectIfLoadable(knownConfigPath);
|
|
@@ -969,7 +995,12 @@ function createServer(connection) {
|
|
|
969
995
|
}
|
|
970
996
|
const filePath = filePathFromUri(uri);
|
|
971
997
|
if (filePath === void 0) return;
|
|
972
|
-
|
|
998
|
+
let configPath;
|
|
999
|
+
try {
|
|
1000
|
+
configPath = await findNearestConfigPathForFile(filePath);
|
|
1001
|
+
} catch {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
973
1004
|
if (configPath === void 0) return;
|
|
974
1005
|
documentConfigPaths.set(uri, configPath);
|
|
975
1006
|
const project = await resolveProjectIfLoadable(configPath);
|
|
@@ -985,26 +1016,44 @@ function createServer(connection) {
|
|
|
985
1016
|
}
|
|
986
1017
|
}
|
|
987
1018
|
async function resolveProject(configPath) {
|
|
988
|
-
const
|
|
989
|
-
if (
|
|
990
|
-
|
|
991
|
-
if (existingLoad !== void 0) return existingLoad;
|
|
992
|
-
return queueProjectLoad(configPath);
|
|
1019
|
+
const entry = managedProjects.get(configPath);
|
|
1020
|
+
if (entry === void 0) return startProjectLoad(configPath);
|
|
1021
|
+
return entry.status === "loaded" ? entry.project : entry.load;
|
|
993
1022
|
}
|
|
994
1023
|
function refreshProject(configPath) {
|
|
995
|
-
return
|
|
1024
|
+
return startProjectLoad(configPath);
|
|
996
1025
|
}
|
|
997
|
-
function
|
|
998
|
-
const
|
|
999
|
-
|
|
1026
|
+
function startProjectLoad(configPath) {
|
|
1027
|
+
const existing = managedProjects.get(configPath);
|
|
1028
|
+
const previousLoad = existing?.status === "loading" ? existing.load : void 0;
|
|
1029
|
+
const hadLoadedProject = existing?.status === "loaded" || existing?.status === "loading" && existing.hadLoadedProject;
|
|
1030
|
+
const load = (previousLoad ?? Promise.resolve(void 0)).catch(() => void 0).then(() => loadProject(configPath)).then((project) => {
|
|
1031
|
+
if (isCurrentLoad(configPath, load)) if (hasManagedDocuments(configPath)) managedProjects.set(configPath, {
|
|
1032
|
+
status: "loaded",
|
|
1033
|
+
project
|
|
1034
|
+
});
|
|
1035
|
+
else managedProjects.delete(configPath);
|
|
1036
|
+
return project;
|
|
1037
|
+
});
|
|
1038
|
+
managedProjects.set(configPath, {
|
|
1039
|
+
status: "loading",
|
|
1040
|
+
load,
|
|
1041
|
+
hadLoadedProject
|
|
1000
1042
|
});
|
|
1001
|
-
projectLoads.set(configPath, load);
|
|
1002
1043
|
return load;
|
|
1003
1044
|
}
|
|
1045
|
+
function isCurrentLoad(configPath, load) {
|
|
1046
|
+
const entry = managedProjects.get(configPath);
|
|
1047
|
+
return entry?.status === "loading" && entry.load === load;
|
|
1048
|
+
}
|
|
1004
1049
|
async function loadProject(configPath) {
|
|
1005
1050
|
const resolution = await resolveConfigInputs(configPath);
|
|
1006
|
-
const artifacts =
|
|
1007
|
-
|
|
1051
|
+
const artifacts = createProjectArtifacts({
|
|
1052
|
+
inputs: resolution.inputs,
|
|
1053
|
+
controlStack: resolution.controlStack,
|
|
1054
|
+
getText: (uri) => documents.get(uri)?.getText()
|
|
1055
|
+
});
|
|
1056
|
+
return resolution.formatter === void 0 ? {
|
|
1008
1057
|
configPath,
|
|
1009
1058
|
inputs: resolution.inputs,
|
|
1010
1059
|
controlStack: resolution.controlStack,
|
|
@@ -1016,14 +1065,14 @@ function createServer(connection) {
|
|
|
1016
1065
|
controlStack: resolution.controlStack,
|
|
1017
1066
|
artifacts
|
|
1018
1067
|
};
|
|
1019
|
-
projects.set(configPath, project);
|
|
1020
|
-
return project;
|
|
1021
1068
|
}
|
|
1022
1069
|
function stopManagingProject(configPath) {
|
|
1023
|
-
const
|
|
1070
|
+
const entry = managedProjects.get(configPath);
|
|
1071
|
+
const hadProject = entry?.status === "loaded" || entry?.status === "loading" && entry.hadLoadedProject;
|
|
1072
|
+
managedProjects.delete(configPath);
|
|
1024
1073
|
for (const document of documents.all()) if (documentConfigPaths.get(document.uri) === configPath) {
|
|
1025
1074
|
documentConfigPaths.delete(document.uri);
|
|
1026
|
-
if (hadProject) sendDiagnostics({
|
|
1075
|
+
if (hadProject && !clientCapabilities.pullDiagnostics) sendDiagnostics({
|
|
1027
1076
|
uri: document.uri,
|
|
1028
1077
|
diagnostics: []
|
|
1029
1078
|
});
|
|
@@ -1032,6 +1081,13 @@ function createServer(connection) {
|
|
|
1032
1081
|
async function republishOpenDocumentsForConfig(configPath) {
|
|
1033
1082
|
for (const document of documents.all()) {
|
|
1034
1083
|
if (documentConfigPaths.get(document.uri) === configPath) {
|
|
1084
|
+
if (await resolveProjectForDocument(document.uri) === void 0) {
|
|
1085
|
+
sendDiagnostics({
|
|
1086
|
+
uri: document.uri,
|
|
1087
|
+
diagnostics: []
|
|
1088
|
+
});
|
|
1089
|
+
continue;
|
|
1090
|
+
}
|
|
1035
1091
|
await publish(document.uri);
|
|
1036
1092
|
continue;
|
|
1037
1093
|
}
|
|
@@ -1052,13 +1108,8 @@ function createServer(connection) {
|
|
|
1052
1108
|
async function formatDocument(uri) {
|
|
1053
1109
|
const document = documents.get(uri);
|
|
1054
1110
|
if (document === void 0) return [];
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
project = await resolveProjectForDocument(uri);
|
|
1058
|
-
} catch {
|
|
1059
|
-
return [];
|
|
1060
|
-
}
|
|
1061
|
-
if (project === void 0 || !project.inputs.includes(uri)) return [];
|
|
1111
|
+
const project = await resolveProjectForDocument(uri);
|
|
1112
|
+
if (project === void 0) return [];
|
|
1062
1113
|
const source = document.getText();
|
|
1063
1114
|
let formatted;
|
|
1064
1115
|
try {
|
|
@@ -1081,62 +1132,47 @@ function createServer(connection) {
|
|
|
1081
1132
|
async function semanticTokensForDocument(uri, range) {
|
|
1082
1133
|
const document = documents.get(uri);
|
|
1083
1134
|
if (document === void 0) return emptySemanticTokens();
|
|
1084
|
-
|
|
1085
|
-
if (text.length > semanticTokenSourceLimit) return emptySemanticTokens();
|
|
1135
|
+
if (document.getText().length > semanticTokenSourceLimit) return emptySemanticTokens();
|
|
1086
1136
|
const project = await resolveProjectForDocument(uri);
|
|
1087
1137
|
if (project === void 0) return emptySemanticTokens();
|
|
1088
|
-
const
|
|
1089
|
-
if (
|
|
1138
|
+
const artifacts = project.artifacts.document(uri);
|
|
1139
|
+
if (artifacts === void 0) return emptySemanticTokens();
|
|
1090
1140
|
return buildSemanticTokens({
|
|
1091
|
-
document:
|
|
1092
|
-
sourceFile:
|
|
1093
|
-
symbolTable: project.artifacts.
|
|
1141
|
+
document: artifacts.document,
|
|
1142
|
+
sourceFile: artifacts.sourceFile,
|
|
1143
|
+
symbolTable: project.artifacts.symbolTable(),
|
|
1094
1144
|
scalarTypes: project.controlStack.scalarTypes
|
|
1095
1145
|
}, range);
|
|
1096
1146
|
}
|
|
1097
1147
|
async function completeDocument(uri, position) {
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
} catch {
|
|
1104
|
-
return [];
|
|
1105
|
-
}
|
|
1106
|
-
if (project === void 0 || !project.inputs.includes(uri)) return [];
|
|
1107
|
-
const cached = currentDocumentArtifact(project, uri, document.getText());
|
|
1108
|
-
const symbolTable = project.artifacts.getSymbolTable();
|
|
1109
|
-
if (cached === void 0 || symbolTable === void 0) return [];
|
|
1148
|
+
if (documents.get(uri) === void 0) return [];
|
|
1149
|
+
const project = await resolveProjectForDocument(uri);
|
|
1150
|
+
if (project === void 0) return [];
|
|
1151
|
+
const artifacts = project.artifacts.document(uri);
|
|
1152
|
+
if (artifacts === void 0) return [];
|
|
1110
1153
|
try {
|
|
1111
1154
|
return [...providePslCompletionItems({
|
|
1112
1155
|
context: classifyPslCompletionContext({
|
|
1113
|
-
document:
|
|
1114
|
-
sourceFile:
|
|
1156
|
+
document: artifacts.document,
|
|
1157
|
+
sourceFile: artifacts.sourceFile,
|
|
1115
1158
|
position
|
|
1116
1159
|
}),
|
|
1117
|
-
sourceFile:
|
|
1160
|
+
sourceFile: artifacts.sourceFile,
|
|
1118
1161
|
candidates: {
|
|
1119
1162
|
scalarTypes: project.controlStack.scalarTypes,
|
|
1120
1163
|
pslBlockDescriptors: project.controlStack.pslBlockDescriptors,
|
|
1121
|
-
symbolTable
|
|
1164
|
+
symbolTable: project.artifacts.symbolTable()
|
|
1122
1165
|
},
|
|
1123
|
-
clientSupportsSnippets
|
|
1166
|
+
clientSupportsSnippets: clientCapabilities.completionSnippets
|
|
1124
1167
|
})];
|
|
1125
1168
|
} catch {
|
|
1126
1169
|
return [];
|
|
1127
1170
|
}
|
|
1128
1171
|
}
|
|
1129
|
-
function currentDocumentArtifact(project, uri, text) {
|
|
1130
|
-
const cached = project.artifacts.getDocument(uri);
|
|
1131
|
-
if (cached?.sourceFile.text === text) return cached;
|
|
1132
|
-
if (project.artifacts.update(uri, text, project.inputs, project.controlStack) === null) return;
|
|
1133
|
-
return project.artifacts.getDocument(uri);
|
|
1134
|
-
}
|
|
1135
1172
|
connection.onInitialize(async (params) => {
|
|
1136
|
-
rootPath = resolveRootPath(params
|
|
1173
|
+
rootPath = resolveRootPath(params);
|
|
1137
1174
|
watchedConfigGlob = join(rootPath, "**", CONFIG_FILENAME);
|
|
1138
|
-
|
|
1139
|
-
clientSupportsSnippets = clientSupportsCompletionSnippets(params);
|
|
1175
|
+
clientCapabilities = resolveClientCapabilities(params);
|
|
1140
1176
|
return { capabilities: {
|
|
1141
1177
|
textDocumentSync: TextDocumentSyncKind.Incremental,
|
|
1142
1178
|
documentFormattingProvider: true,
|
|
@@ -1146,11 +1182,15 @@ function createServer(connection) {
|
|
|
1146
1182
|
full: true,
|
|
1147
1183
|
range: true
|
|
1148
1184
|
},
|
|
1149
|
-
completionProvider: { triggerCharacters: ["."] }
|
|
1185
|
+
completionProvider: { triggerCharacters: ["."] },
|
|
1186
|
+
...clientCapabilities.pullDiagnostics ? { diagnosticProvider: {
|
|
1187
|
+
interFileDependencies: false,
|
|
1188
|
+
workspaceDiagnostics: false
|
|
1189
|
+
} } : {}
|
|
1150
1190
|
} };
|
|
1151
1191
|
});
|
|
1152
1192
|
connection.onInitialized(() => {
|
|
1153
|
-
if (
|
|
1193
|
+
if (clientCapabilities.watchedFilesRegistration) connection.sendRequest(RegistrationRequest.type, { registrations: [{
|
|
1154
1194
|
id: "prisma-next-config-watcher",
|
|
1155
1195
|
method: DidChangeWatchedFilesNotification.type.method,
|
|
1156
1196
|
registerOptions: { watchers: [{ globPattern: watchedConfigGlob }] }
|
|
@@ -1160,43 +1200,52 @@ function createServer(connection) {
|
|
|
1160
1200
|
connection.onDidChangeWatchedFiles(async (params) => {
|
|
1161
1201
|
const changedConfigPaths = configPathsFromWatchedChanges(params.changes.map((change) => filePathFromUri(change.uri)));
|
|
1162
1202
|
for (const configPath of changedConfigPaths) {
|
|
1163
|
-
try {
|
|
1203
|
+
if (managedProjects.has(configPath)) try {
|
|
1164
1204
|
await refreshProject(configPath);
|
|
1165
1205
|
} catch {
|
|
1166
1206
|
stopManagingProject(configPath);
|
|
1167
1207
|
continue;
|
|
1168
1208
|
}
|
|
1169
|
-
await republishOpenDocumentsForConfig(configPath);
|
|
1209
|
+
if (!clientCapabilities.pullDiagnostics) await republishOpenDocumentsForConfig(configPath);
|
|
1170
1210
|
}
|
|
1211
|
+
if (clientCapabilities.pullDiagnostics && clientCapabilities.diagnosticsRefresh && changedConfigPaths.size > 0 && !disposed) connection.languages.diagnostics.refresh().catch(() => void 0);
|
|
1171
1212
|
});
|
|
1172
1213
|
connection.onDocumentFormatting((params) => formatDocument(params.textDocument.uri));
|
|
1173
1214
|
connection.onCompletion((params) => completeDocument(params.textDocument.uri, params.position));
|
|
1174
1215
|
connection.languages.semanticTokens.on((params) => semanticTokensForDocument(params.textDocument.uri));
|
|
1175
1216
|
connection.languages.semanticTokens.onRange((params) => semanticTokensForDocument(params.textDocument.uri, params.range));
|
|
1217
|
+
connection.languages.diagnostics.on(async (params) => {
|
|
1218
|
+
const project = await resolveProjectForDocument(params.textDocument.uri);
|
|
1219
|
+
if (project === void 0) return {
|
|
1220
|
+
kind: DocumentDiagnosticReportKind.Full,
|
|
1221
|
+
items: []
|
|
1222
|
+
};
|
|
1223
|
+
return buildDocumentDiagnosticReport(project, params.textDocument.uri);
|
|
1224
|
+
});
|
|
1176
1225
|
connection.onFoldingRanges(async (params) => {
|
|
1177
|
-
|
|
1178
|
-
try {
|
|
1179
|
-
project = await resolveProjectForDocument(params.textDocument.uri);
|
|
1180
|
-
} catch {
|
|
1181
|
-
return [];
|
|
1182
|
-
}
|
|
1226
|
+
const project = await resolveProjectForDocument(params.textDocument.uri);
|
|
1183
1227
|
if (project === void 0) return [];
|
|
1184
|
-
const
|
|
1185
|
-
if (
|
|
1186
|
-
return computeFoldingRanges(
|
|
1228
|
+
const artifacts = project.artifacts.document(params.textDocument.uri);
|
|
1229
|
+
if (artifacts === void 0) return [];
|
|
1230
|
+
return computeFoldingRanges(artifacts.document, artifacts.sourceFile);
|
|
1187
1231
|
});
|
|
1188
1232
|
documents.onDidOpen((event) => {
|
|
1233
|
+
artifactsForDocument(event.document.uri)?.documentChanged(event.document.uri);
|
|
1234
|
+
if (clientCapabilities.pullDiagnostics) return;
|
|
1189
1235
|
publishSafely(event.document.uri);
|
|
1190
1236
|
});
|
|
1191
1237
|
documents.onDidChangeContent((event) => {
|
|
1238
|
+
artifactsForDocument(event.document.uri)?.documentChanged(event.document.uri);
|
|
1239
|
+
if (clientCapabilities.pullDiagnostics) return;
|
|
1192
1240
|
publishSafely(event.document.uri);
|
|
1193
1241
|
});
|
|
1194
1242
|
documents.onDidClose((event) => {
|
|
1195
1243
|
const uri = event.document.uri;
|
|
1196
1244
|
const configPath = documentConfigPaths.get(uri);
|
|
1197
|
-
|
|
1245
|
+
artifactsForDocument(uri)?.documentClosed(uri);
|
|
1198
1246
|
documentConfigPaths.delete(uri);
|
|
1199
|
-
|
|
1247
|
+
if (configPath !== void 0) dropProjectWithoutManagedDocuments(configPath);
|
|
1248
|
+
if (!clientCapabilities.pullDiagnostics) sendDiagnostics({
|
|
1200
1249
|
uri,
|
|
1201
1250
|
diagnostics: []
|
|
1202
1251
|
});
|
|
@@ -1205,20 +1254,39 @@ function createServer(connection) {
|
|
|
1205
1254
|
connection.listen();
|
|
1206
1255
|
function artifactsForDocument(uri) {
|
|
1207
1256
|
const configPath = documentConfigPaths.get(uri);
|
|
1208
|
-
|
|
1257
|
+
if (configPath === void 0) return;
|
|
1258
|
+
const entry = managedProjects.get(configPath);
|
|
1259
|
+
return entry?.status === "loaded" ? entry.project.artifacts : void 0;
|
|
1260
|
+
}
|
|
1261
|
+
function hasManagedDocuments(configPath) {
|
|
1262
|
+
for (const managedConfigPath of documentConfigPaths.values()) if (managedConfigPath === configPath) return true;
|
|
1263
|
+
return false;
|
|
1264
|
+
}
|
|
1265
|
+
function dropProjectWithoutManagedDocuments(configPath) {
|
|
1266
|
+
if (hasManagedDocuments(configPath)) return;
|
|
1267
|
+
if (managedProjects.get(configPath)?.status === "loaded") managedProjects.delete(configPath);
|
|
1209
1268
|
}
|
|
1210
1269
|
return {
|
|
1211
1270
|
dispose: () => {
|
|
1212
1271
|
disposed = true;
|
|
1213
1272
|
connection.dispose();
|
|
1214
1273
|
},
|
|
1215
|
-
getDocumentAst: (uri) => artifactsForDocument(uri)?.
|
|
1216
|
-
getProjectSymbolTable: (uri) => artifactsForDocument(uri)?.
|
|
1274
|
+
getDocumentAst: (uri) => artifactsForDocument(uri)?.document(uri),
|
|
1275
|
+
getProjectSymbolTable: (uri) => artifactsForDocument(uri)?.symbolTable()
|
|
1217
1276
|
};
|
|
1218
1277
|
}
|
|
1219
1278
|
function emptySemanticTokens() {
|
|
1220
1279
|
return { data: [] };
|
|
1221
1280
|
}
|
|
1281
|
+
function toDiagnostics(computed) {
|
|
1282
|
+
return computed.map((diagnostic) => ({
|
|
1283
|
+
range: diagnostic.range,
|
|
1284
|
+
message: diagnostic.message,
|
|
1285
|
+
code: diagnostic.code,
|
|
1286
|
+
severity: toLspSeverity(diagnostic.severity),
|
|
1287
|
+
source: "prisma-next"
|
|
1288
|
+
}));
|
|
1289
|
+
}
|
|
1222
1290
|
function toLspSeverity(severity) {
|
|
1223
1291
|
switch (severity) {
|
|
1224
1292
|
case ParseDiagnosticSeverity.Warning: return DiagnosticSeverity.Warning;
|
|
@@ -1227,15 +1295,25 @@ function toLspSeverity(severity) {
|
|
|
1227
1295
|
default: return DiagnosticSeverity.Error;
|
|
1228
1296
|
}
|
|
1229
1297
|
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1298
|
+
const noClientCapabilities = {
|
|
1299
|
+
watchedFilesRegistration: false,
|
|
1300
|
+
completionSnippets: false,
|
|
1301
|
+
pullDiagnostics: false,
|
|
1302
|
+
diagnosticsRefresh: false
|
|
1303
|
+
};
|
|
1304
|
+
function resolveClientCapabilities(params) {
|
|
1305
|
+
return {
|
|
1306
|
+
watchedFilesRegistration: params.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration === true,
|
|
1307
|
+
completionSnippets: params.capabilities.textDocument?.completion?.completionItem?.snippetSupport === true,
|
|
1308
|
+
pullDiagnostics: params.capabilities.textDocument?.diagnostic !== void 0,
|
|
1309
|
+
diagnosticsRefresh: params.capabilities.workspace?.diagnostics?.refreshSupport === true
|
|
1310
|
+
};
|
|
1235
1311
|
}
|
|
1236
|
-
function resolveRootPath(
|
|
1237
|
-
|
|
1238
|
-
if (
|
|
1312
|
+
function resolveRootPath(params) {
|
|
1313
|
+
const workspaceFolder = params.workspaceFolders?.[0];
|
|
1314
|
+
if (workspaceFolder !== void 0) return fileURLToPath(workspaceFolder.uri);
|
|
1315
|
+
if (params.rootUri) return fileURLToPath(params.rootUri);
|
|
1316
|
+
if (params.rootPath) return params.rootPath;
|
|
1239
1317
|
return process.cwd();
|
|
1240
1318
|
}
|
|
1241
1319
|
function filePathFromUri(uri) {
|