UNPKG

els-addon-typed-templates

Version:
132 lines (116 loc) 5.38 kB
import { CompletionFunctionParams } from '../interfaces'; import { Project } from '@lifeart/ember-language-server'; import { CompletionItem } from 'vscode-languageserver'; import { mergeResults, normalizeAngleTagName, toFilePath } from "./../lib/utils"; import { serviceForRoot, componentsForService, typeForPath, serverForProject } from './../lib/ts-service'; import { virtualTemplateFileName, virtualComponentTemplateFileName } from "./../lib/resolvers"; import * as fs from 'fs'; import { positionForItem } from './../lib/ast-helpers'; import { getFirstASTNode } from './../lib/ast-parser'; import { normalizeCompletions } from './../lib/ls-utils'; import { isHBS } from './../lib/utils'; import VirtualDocumentProvider from './virtual-document'; import { isParamPath, isArgumentName, realPathName, canHandle, isExternalComponentArgument, relplaceFocusPathForExternalComponentArgument, isEachArgument, normalizeArgumentName } from "./../lib/ast-helpers"; export default class CompletionProvider { constructor(private project: Project, private virtualDocument: VirtualDocumentProvider) { } async onComplete( { results, focusPath, type, textDocument }: CompletionFunctionParams ): Promise<CompletionItem[] | null> { if (!canHandle(type, focusPath)) { return results; } try { const isParam = isParamPath(focusPath); const isExternalComponentArg = isExternalComponentArgument(focusPath); let originalComponentName = ''; if (isExternalComponentArg) { focusPath = relplaceFocusPathForExternalComponentArgument(focusPath); originalComponentName = normalizeAngleTagName(focusPath.parent.tag); } const projectRoot = this.project.root; const service = serviceForRoot(projectRoot); const server = serverForProject(projectRoot); const componentsMap = componentsForService(service, true); let templatePath = toFilePath(textDocument.uri); if (isExternalComponentArg) { let possibleTemplates = server.getRegistry(projectRoot).component[originalComponentName] || []; possibleTemplates.forEach((el) => { if (isHBS(el)) { templatePath = el; } }) } const componentMeta = typeForPath(projectRoot, templatePath); if (!componentMeta) { return null; } let isArg = false; const isArrayCase = isEachArgument(focusPath); let realPath = realPathName(focusPath); let content = focusPath.content; if (isArgumentName(realPath) || isExternalComponentArg) { isArg = true; if (isExternalComponentArg) { realPath = normalizeArgumentName(focusPath.node.name); let realContent = fs.readFileSync(templatePath, 'utf8'); content = `{{${realPath}}}${realContent}`; } else { realPath = normalizeArgumentName(realPath); } } const fileName = virtualTemplateFileName(templatePath); const fullFileName = virtualComponentTemplateFileName(templatePath); const { pos } = this.virtualDocument.createVirtualTemplate( componentsMap, fileName, { templatePath, realPath, isArg, isParam, isArrayCase } ); let nodePosition = positionForItem(focusPath.node); let tsResults: any = null; try { if (isExternalComponentArg) { let node = (getFirstASTNode(content) as any); if (node === null) { return []; } nodePosition = positionForItem(node.path); } let markId = `; /*@path-mark ${nodePosition}*/`; let tpl = this.virtualDocument.createFullVirtualTemplate(componentsMap, templatePath, fullFileName, textDocument.uri, content as string, componentMeta); tsResults = service.getCompletionsAtPosition(fullFileName, tpl.indexOf(markId), { includeInsertTextCompletions: true }); if (!tsResults || tsResults && tsResults.entries > 100) { throw new Error("Too many or no results"); } } catch (e) { tsResults = service.getCompletionsAtPosition(fileName, pos, { includeInsertTextCompletions: true }); } if (tsResults && tsResults.entries.length > 100) { return results; } let data = normalizeCompletions(tsResults, realPath, isArg); return mergeResults(results, data) as CompletionItem[]; } catch (e) { console.error(e, e.ProgramFiles); } return results; } }