@prisma/language-server
Version:
Prisma Language Server
225 lines • 10.5 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handleDiagnosticsRequest = handleDiagnosticsRequest;
exports.handleDefinitionRequest = handleDefinitionRequest;
exports.handleDocumentFormatting = handleDocumentFormatting;
exports.handleHoverRequest = handleHoverRequest;
exports.handleCompletionRequest = handleCompletionRequest;
exports.handleReferencesRequest = handleReferencesRequest;
exports.handleRenameRequest = handleRenameRequest;
exports.handleCompletionResolveRequest = handleCompletionResolveRequest;
exports.handleCodeActions = handleCodeActions;
exports.handleDocumentSymbol = handleDocumentSymbol;
const vscode_languageserver_1 = require("vscode-languageserver");
const format_1 = __importDefault(require("./prisma-schema-wasm/format"));
const lint_1 = __importDefault(require("./prisma-schema-wasm/lint"));
const code_actions_1 = require("./code-actions");
const rename_1 = require("./code-actions/rename");
const validations_1 = require("./validations");
const ast_1 = require("./ast");
const completions_1 = require("./completions");
const Schema_1 = require("./Schema");
const DiagnosticMap_1 = require("./DiagnosticMap");
const references_1 = __importDefault(require("./prisma-schema-wasm/references"));
const hover_1 = __importDefault(require("./prisma-schema-wasm/hover"));
function handleDiagnosticsRequest(schema, onError) {
const res = (0, lint_1.default)(schema, (errorMessage) => {
if (onError) {
onError(errorMessage);
}
});
const diagnostics = new DiagnosticMap_1.DiagnosticMap(schema.documents.map((doc) => doc.uri));
if (res.some((diagnostic) => diagnostic.text === "Field declarations don't require a `:`." ||
diagnostic.text === 'Model declarations have to be indicated with the `model` keyword.')) {
if (onError) {
onError("You might currently be viewing a Prisma 1 datamodel which is based on the GraphQL syntax. The current Prisma Language Server doesn't support this syntax. If you are handling a Prisma 1 datamodel, please change the file extension to `.graphql` so the new Prisma Language Server does not get triggered anymore.");
}
}
for (const diag of res) {
const previewNotKnownRegex = /The preview feature \"[a-zA-Z]+\" is not known/;
const uri = diag.file_name;
const document = schema.findDocByUri(uri);
if (!document) {
continue;
}
const diagnostic = {
range: {
start: document.positionAt(diag.start),
end: document.positionAt(diag.end),
},
message: previewNotKnownRegex.test(diag.text)
? `${diag.text}.\nIf this is unexpected, it might be due to your editor's Prisma Extension being out of date.`
: diag.text,
source: 'Prisma',
};
if (diag.is_warning) {
diagnostic.severity = vscode_languageserver_1.DiagnosticSeverity.Warning;
}
else {
diagnostic.severity = vscode_languageserver_1.DiagnosticSeverity.Error;
}
diagnostics.add(uri, diagnostic);
}
(0, validations_1.validateIgnoredBlocks)(schema, diagnostics);
return diagnostics;
}
/**
* @todo Use official schema.prisma parser. This is a workaround!
*/
function handleDefinitionRequest(schema, initiatingDocument, params) {
const position = params.position;
const word = (0, ast_1.getWordAtPosition)(initiatingDocument, position);
if (word === '') {
return;
}
// get start position of block
const results = schema
.linesAsArray()
.map(({ document, lineIndex, text }) => {
if ((text.includes('model') && text.includes(word)) ||
(text.includes('type') && text.includes(word)) ||
(text.includes('enum') && text.includes(word))) {
return [document, lineIndex];
}
})
.filter((result) => result !== undefined);
if (results.length === 0) {
return;
}
const foundBlocks = results
.map(([document, lineNo]) => {
const block = (0, ast_1.getBlockAtPosition)(document.uri, lineNo, schema);
if (block && block.name === word && block.range.start.line === lineNo) {
return block;
}
})
.filter((block) => block !== undefined);
if (foundBlocks.length !== 1) {
return;
}
if (!foundBlocks[0]) {
return;
}
return [
{
targetUri: foundBlocks[0].definingDocument.uri,
targetRange: foundBlocks[0].range,
targetSelectionRange: foundBlocks[0].nameRange,
},
];
}
/**
* This handler provides the modification to the document to be formatted.
*/
function handleDocumentFormatting(schema, initiatingDocument, params, onError) {
const formatted = (0, format_1.default)(schema, initiatingDocument, params, onError);
return [vscode_languageserver_1.TextEdit.replace((0, ast_1.fullDocumentRange)(initiatingDocument), formatted)];
}
function handleHoverRequest(schema, initiatingDocument, params, onError) {
return (0, hover_1.default)(schema, initiatingDocument, params, onError);
}
/**
*
* This handler provides the initial list of the completion items.
*/
function handleCompletionRequest(schema, document, params, onError) {
return (0, completions_1.prismaSchemaWasmCompletions)(schema, params, onError) || (0, completions_1.localCompletions)(schema, document, params, onError);
}
function handleReferencesRequest(schema, params, onError) {
return (0, references_1.default)(schema, params, onError);
}
function handleRenameRequest(schema, initiatingDocument, params) {
const schemaLines = schema.linesAsArray();
const position = params.position;
const block = (0, ast_1.getBlockAtPosition)(initiatingDocument.uri, position.line, schema);
if (!block) {
return undefined;
}
const currentLine = block.definingDocument.lines[params.position.line].text;
const isDatamodelBlockRename = (0, rename_1.isDatamodelBlockName)(position, block, schema, initiatingDocument);
const isMappable = ['model', 'enum', 'view'].includes(block.type);
const needsMap = !isDatamodelBlockRename ? true : isMappable;
const isEnumValueRename = (0, rename_1.isEnumValue)(currentLine, params.position, block, initiatingDocument);
const isValidFieldRename = (0, rename_1.isValidFieldName)(currentLine, params.position, block, initiatingDocument);
const isRelationFieldRename = isValidFieldRename && (0, rename_1.isRelationField)(currentLine, schema);
if (isDatamodelBlockRename || isEnumValueRename || isValidFieldRename) {
const edits = [];
const currentName = (0, rename_1.extractCurrentName)(currentLine, isDatamodelBlockRename, isEnumValueRename, isValidFieldRename, initiatingDocument, params.position);
let lineNumberOfDefinition = position.line;
let blockOfDefinition = block;
let lineOfDefinitionContent = currentLine;
if (isDatamodelBlockRename) {
// get definition of model or enum
const matchBlockBeginning = new RegExp(`\\s*(${block.type})\\s+(${currentName})\\s*({)`, 'g');
const lineOfDefinition = schemaLines.find((line) => matchBlockBeginning.test(line.text));
if (!lineOfDefinition) {
return;
}
const { document: definitionDoc, lineIndex, text } = lineOfDefinition;
lineNumberOfDefinition = lineIndex;
lineOfDefinitionContent = text;
const definitionBlockAtPosition = (0, ast_1.getBlockAtPosition)(definitionDoc.uri, lineNumberOfDefinition, schema);
if (!definitionBlockAtPosition) {
return;
}
blockOfDefinition = definitionBlockAtPosition;
}
// rename marked string
edits.push((0, rename_1.insertBasicRename)(params.newName, currentName, initiatingDocument, lineNumberOfDefinition));
// check if map exists already
if (!isRelationFieldRename &&
!(0, rename_1.mapExistsAlready)(lineOfDefinitionContent, schema, blockOfDefinition, isDatamodelBlockRename) &&
needsMap) {
// add map attribute
edits.push((0, rename_1.insertMapAttribute)(currentName, position, blockOfDefinition, isDatamodelBlockRename));
}
// rename references
if (isDatamodelBlockRename) {
edits.push((0, rename_1.renameReferencesForModelName)(currentName, params.newName, schema));
}
else if (isEnumValueRename) {
edits.push((0, rename_1.renameReferencesForEnumValue)(currentName, params.newName, schema, blockOfDefinition.name));
}
else if (isValidFieldRename) {
edits.push((0, rename_1.renameReferencesForFieldName)(currentName, params.newName, schema, blockOfDefinition, isRelationFieldRename));
}
(0, rename_1.printLogMessage)(currentName, params.newName, isDatamodelBlockRename, isValidFieldRename, isEnumValueRename, block.type);
return {
changes: (0, rename_1.mergeEditMaps)(edits),
};
}
return;
}
/**
*
* @param item This handler resolves additional information for the item selected in the completion list.
*/
function handleCompletionResolveRequest(item) {
return item;
}
function handleCodeActions(schema, initiatingDocument, params, onError) {
if (!params.context.diagnostics.length) {
return [];
}
return (0, code_actions_1.quickFix)(schema, initiatingDocument, params, onError);
}
function handleDocumentSymbol(params, document) {
const schema = Schema_1.PrismaSchema.singleFile(document);
return Array.from((0, ast_1.getBlocks)(schema), (block) => ({
kind: {
model: vscode_languageserver_1.SymbolKind.Class,
enum: vscode_languageserver_1.SymbolKind.Enum,
type: vscode_languageserver_1.SymbolKind.Interface,
view: vscode_languageserver_1.SymbolKind.Class,
datasource: vscode_languageserver_1.SymbolKind.Struct,
generator: vscode_languageserver_1.SymbolKind.Function,
}[block.type],
name: block.name,
range: block.range,
selectionRange: block.nameRange,
}));
}
//# sourceMappingURL=MessageHandler.js.map