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 , private virtualDocument ) { } async onComplete ( { results , focusPath , type , textDocument } ) { 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 = 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 ; } }