!function(mod){"object"==typeof exports&&"object"==typeof module?mod(require("../lib/infer"),require("../lib/tern"),require("../lib/signal"),require):"function"==typeof define&&define.amd?define(["../lib/infer","../lib/tern","../lib/signal"],mod):mod(tern,tern,tern.signal)}(function(infer,tern,signal,require){"use strict";function Modules(server,options){this.server=server,this.options=options||{},this.modules=Object.create(null),this.nonRelative=Object.create(null),this.knownModules=Object.create(null),this.resolvers=[],this.modNameTests=[],this.importTests=[],this.completableTypes=Object.create(null)}function resolvePath(parent,sub){if(/^https?:|^\//.test(sub))return sub;var m;for(parent&&!/\/$/.test(parent)&&(parent+="/");m=/^\.(\.)?\//.exec(sub);){if(m[1]&&parent.length>1){var lastSlash=parent.lastIndexOf("/",parent.length-2);parent=-1==lastSlash?"":parent.slice(0,lastSlash+1)}sub=sub.slice(m[0].length)}return parent+sub}function dirName(path){var lastSlash=path.lastIndexOf("/");return-1==lastSlash?"":path.slice(0,lastSlash+1)}function baseName(path){var lastSlash=path.lastIndexOf("/");return-1==lastSlash?path:path.slice(lastSlash+1)}function defaultResolver(name,parentFile){if(/^\.\.?\//.test(name)){var path=resolvePath(dirName(parentFile),name),server=infer.cx().parent;return server.findFile(path)?path:server.findFile(path+".js")?path+".js":void 0}}var fs,path;function isRelative(path){return/^\.\.?\//.test(path)}function filter(word,string,query){return!1===query.filter||!word||0==(query.caseInsensitive?string.toLowerCase():string).indexOf(word)}function preCondenseReach(state){var mods=infer.cx().parent.mod.modules.modules,node=state.roots["!modules"]=new infer.Obj(null);for(var name in mods){var mod=mods[name],id=mod.origin||name,prop=node.defProp(id.replace(/\./g,"`"));prop.origin=mod.origin,mod.propagate(prop)}}function postLoadDef(data){var cx=infer.cx(),me=cx.parent.mod.modules,mods=cx.definitions[data["!name"]]["!modules"];if(mods)for(var name in mods.props){var origin=name.replace(/`/g,"."),mod=me.get(origin);mod.origin=origin,mods.props[name].propagate(mod)}var known=cx.definitions[data["!name"]]["!known_modules"];if(known)for(var name in known.props)me.knownModules[name.replace(/`/g,".")]=known.props[name]}function findTypeAt(_file,_pos,expr,type){if(!expr)return type;var me,modType=infer.cx().parent.mod.modules.getModType(expr.node);if(!modType)return type;var inner=modType.getType(!1)||{};return(type=Object.create(type)).origin=modType.origin||inner.origin,type.originNode=modType.originNode||inner.originNode,modType.doc?type.doc=modType.doc:inner.doc&&(type.doc=inner.doc),modType.url?type.url=modType.url:inner.url&&(type.url=inner.url),type}function findCompletions(file,query){var me=infer.cx().parent.mod.modules,wordEnd=tern.resolvePos(file,query.end),types=me.completableTypes,expr=infer.findExpressionAround(file.ast,null,wordEnd,file.scope,function(type){return type in types});if(!expr)return null;if(null!=me.isModName(expr.node,wordEnd))return findModuleCompletions(me,file,query,expr.node,wordEnd);var imp=me.isImport(expr.node,wordEnd);return imp&&imp.name&&null!=imp.prop?findImportCompletions(me,file,query,expr.node,imp,wordEnd):void 0}function findImportCompletions(me,file,query,node,imp,wordEnd){var completions=[],word=node.name?node.name.slice(0,wordEnd-node.start):"";query.caseInsensitive&&(word=word.toLowerCase());var modType=me.resolveModule(imp.name,node.sourceFile.name).getType();return modType?(infer.forAllPropertiesOf(modType,function(prop,obj,depth){obj!=infer.cx().protos.Object&&(!1!==query.filter&&word&&0!==(query.caseInsensitive?prop.toLowerCase():prop).indexOf(word)||tern.addCompletion(query,completions,prop,obj&&obj.props[prop],depth))}),{start:tern.outputPos(query,file,node.name?node.start:wordEnd),end:tern.outputPos(query,file,wordEnd),completions:completions,isSpecifier:!0}):null}function findModuleCompletions(me,file,query,argNode,wordEnd){if(!("Literal"!=argNode.type||"string"!=typeof argNode.value||argNode.start>wordEnd||argNode.end-1){var afterSlash=/.*?\/(.*)/.exec(prop)[1],found=val.indexOf(afterSlash);if(found>-1){var dir=val.slice(0,found)+(/.*?\/(.*\/)?/.exec(word)[1]||"");if(dir in pathsSeen)continue;pathsSeen[dir]=!0,this.completeFileName(completions,query,null,word,dir)}}}},completeFileName:function(completions,query,parentFile,word,_dir){var path=parentFile?resolvePath(dirName(parentFile),word):baseName(word);for(var prop in this.modules)if(prop!=parentFile&&filter(path,prop,query)){/\.js$/.test(prop)&&(prop=prop.slice(0,prop.length-3));var added=prop.slice(path.length);tern.addCompletion(query,completions,word+added,this.modules[prop])}},getModType:function(node){var modName=this.isModName(node),imp,prop;if(null==modName&&(imp=this.isImport(node))&&(modName=imp.name,prop=imp.prop),null!=modName){var type=this.resolveModule(modName,node.sourceFile.name);if(prop){var obj=type.getObjType();type=obj&&obj.hasProp(prop)||type.getProp(prop)}return type}}}),require&&(fs=require("fs"),path=require("path"),Modules.prototype.completeFileName=function(completions,query,parentFile,word,dir){var pDir=this.server.projectDir,endSlash=/\/$/.test(word);if(parentFile){var pt=path.resolve(pDir,path.dirname(parentFile),word);dir=endSlash?pt:path.dirname(pt)}var base=endSlash?word:path.dirname(word)+"/",filePart=endSlash?"":path.basename(word),me=this;fs.readdirSync(dir).forEach(function(file){if(!/^\./.test(file)&&filter(filePart,file,query)){var projectPath=me.server.normalizeFilename(path.relative(pDir,path.resolve(dir,file)));if(projectPath==parentFile)return;var value=me.modules[projectPath];/\.js$/.test(file)&&(file=file.slice(0,file.length-3)),tern.addCompletion(query,completions,base+file,value)}})}),tern.registerPlugin("modules",function(server,options){server.mod.modules=new Modules(server,options),server.on("beforeLoad",function(file){file.scope=this.mod.modules.buildWrappingScope(file.scope,file.name,file.ast)}),server.on("afterLoad",function(file){var mod=this.mod.modules.get(file.name);mod.origin=file.name,this.mod.modules.signal("getExports",file,mod)}),server.on("reset",function(){this.mod.modules.modules=Object.create(null)}),server.on("preCondenseReach",preCondenseReach),server.on("postLoadDef",postLoadDef),server.on("typeAt",findTypeAt),server.on("completion",findCompletions)}),tern.defineQueryType("exports",{takesFile:!0,run:function(server,query,file){function describe(aval){var target={},type=aval.getType(!1);target.type=infer.toString(type,3);var doc=aval.doc||type&&type.doc,url=aval.url||type&&type.url;doc&&(target.doc=doc),url&&(target.url=url);var span=tern.getSpan(aval)||type&&tern.getSpan(type);return span&&tern.storeSpan(server,query,span,target),target}var mod=server.mod.modules,known=mod&&mod.modules[file.name];if(!known)return{};var resp=describe(known),type=known.getType(!1);if(type instanceof infer.Obj){var props=resp.props={};for(var prop in type.props)props[prop]=describe(type.props[prop])}return resp}})});