UNPKG

@prisma/language-server

Version:
177 lines 7.37 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDocumentationForBlock = void 0; exports.getBlocks = getBlocks; exports.getDatamodelBlock = getDatamodelBlock; exports.getFieldsFromCurrentBlock = getFieldsFromCurrentBlock; exports.getFieldTypesFromCurrentBlock = getFieldTypesFromCurrentBlock; exports.getCompositeTypeFieldsRecursively = getCompositeTypeFieldsRecursively; const vscode_languageserver_1 = require("vscode-languageserver"); const fields_1 = require("./fields"); const findAtPosition_1 = require("./findAtPosition"); // Note: this is a generator function, which returns a Generator object. // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function* function* getBlocks(schema) { let blockName = ''; let blockType = ''; let blockNameRange; let blockStart = vscode_languageserver_1.Position.create(0, 0); const allowedBlockIdentifiers = ['model', 'type', 'enum', 'datasource', 'generator', 'view']; for (const { document, lineIndex, text } of schema.iterLines()) { // if start of block: `BlockType name {` if (allowedBlockIdentifiers.some((identifier) => text.startsWith(identifier)) && text.includes('{')) { if (blockType && blockNameRange) { // Recover from missing block end yield { type: blockType, range: vscode_languageserver_1.Range.create(blockStart, vscode_languageserver_1.Position.create(lineIndex - 1, 0)), nameRange: blockNameRange, name: blockName, definingDocument: document, }; blockType = ''; blockNameRange = undefined; } const index = text.search(/\s+/); blockType = ~index ? text.slice(0, index) : text; blockName = text.slice(blockType.length, text.length - 2).trimStart(); const startCharacter = text.length - 2 - blockName.length; blockName = blockName.trimEnd(); blockNameRange = vscode_languageserver_1.Range.create(lineIndex, startCharacter, lineIndex, startCharacter + blockName.length); blockStart = vscode_languageserver_1.Position.create(lineIndex, 0); continue; } // if end of block: `}` if (text.startsWith('}') && blockType && blockNameRange) { yield { type: blockType, range: vscode_languageserver_1.Range.create(blockStart, vscode_languageserver_1.Position.create(lineIndex, 1)), nameRange: blockNameRange, name: blockName, definingDocument: document, }; blockType = ''; blockNameRange = undefined; } } } function getDatamodelBlock(blockName, schema) { // get start position of block const results = schema .linesAsArray() .map(({ document, lineIndex, text }) => { if ((text.includes('model') || text.includes('type') || text.includes('enum') || text.includes('view')) && text.includes(blockName)) { return [document, lineIndex]; } }) .filter((result) => result !== undefined); if (results.length === 0) { return; } const foundBlocks = results .map(([document, lineNo]) => { const block = (0, findAtPosition_1.getBlockAtPosition)(document.uri, lineNo, schema); if (block && block.name === blockName) { return block; } }) .filter((block) => block !== undefined); if (foundBlocks.length !== 1) { return; } if (!foundBlocks[0]) { return; } return foundBlocks[0]; } function getFieldsFromCurrentBlock(schema, block, position) { const fieldNames = []; const lines = block.definingDocument.lines; for (let lineIndex = block.range.start.line + 1; lineIndex < block.range.end.line; lineIndex++) { if (!position || lineIndex !== position.line) { const line = lines[lineIndex].text; const fieldName = getFieldNameFromLine(line); if (fieldName) { fieldNames.push(fieldName); } } } return fieldNames; } function getFieldTypesFromCurrentBlock(schema, block, position) { const fieldTypes = new Map(); const fieldTypeNames = {}; let reachedStartLine = false; for (const { document, lineIndex, text: line } of schema.iterLines()) { if (lineIndex === block.range.start.line + 1) { reachedStartLine = true; } if (!reachedStartLine) { continue; } if (lineIndex === block.range.end.line) { break; } if (!line.startsWith('@@') && (!position || lineIndex !== position.line)) { const fieldType = (0, fields_1.getFieldType)(line); if (fieldType !== undefined) { const existingFieldType = fieldTypes.get(fieldType); if (!existingFieldType) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const fieldName = getFieldNameFromLine(line); fieldTypes.set(fieldType, { locations: [{ document, lineIndex }], fieldName }); fieldTypeNames[fieldName] = fieldType; } else { existingFieldType.locations.push({ document, lineIndex }); fieldTypes.set(fieldType, existingFieldType); } } } } return { fieldTypes, fieldTypeNames }; } function getCompositeTypeFieldsRecursively(schema, compositeTypeFieldNames, fieldTypesFromBlock) { const compositeTypeFieldName = compositeTypeFieldNames.shift(); if (!compositeTypeFieldName) { return []; } const fieldTypeNames = fieldTypesFromBlock.fieldTypeNames; const fieldTypeName = fieldTypeNames[compositeTypeFieldName]; if (!fieldTypeName) { return []; } const typeBlock = getDatamodelBlock(fieldTypeName, schema); if (!typeBlock || typeBlock.type !== 'type') { return []; } // if we are not at the end of the composite type, continue recursively if (compositeTypeFieldNames.length) { return getCompositeTypeFieldsRecursively(schema, compositeTypeFieldNames, getFieldTypesFromCurrentBlock(schema, typeBlock)); } else { return getFieldsFromCurrentBlock(schema, typeBlock); } } // TODO (Joël) a regex for \w in first position would be better? function getFieldNameFromLine(line) { if (line.startsWith('//') || line.startsWith('@@')) { return undefined; } const firstPartOfLine = line.replace(/ .*/, ''); return firstPartOfLine; } const getDocumentationForBlock = (block) => { return getDocumentation(block.definingDocument, block.range.start.line, []); }; exports.getDocumentationForBlock = getDocumentationForBlock; const getDocumentation = (document, line, comments) => { const comment = document.lines[line - 1]?.untrimmedText ?? ''; if (comment.startsWith('///')) { comments.unshift(comment.slice(4).trim()); return getDocumentation(document, line - 1, comments); } return comments; }; //# sourceMappingURL=block.js.map