forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathdoc_comment.js
More file actions
1 lines (1 loc) · 12.9 KB
/
Copy pathdoc_comment.js
File metadata and controls
1 lines (1 loc) · 12.9 KB
1
!function(mod){"object"==typeof exports&&"object"==typeof module?mod(require("../lib/infer"),require("../lib/tern"),require("../lib/comment"),require("acorn"),require("acorn-walk")):"function"==typeof define&&define.amd?define(["../lib/infer","../lib/tern","../lib/comment","acorn/dist/acorn","acorn-walk/dist/walk"],mod):mod(tern,tern,tern.comment,acorn,acorn.walk)}(function(infer,tern,comment,acorn,walk){"use strict";var WG_MADEUP=1,WG_STRONG=101;function postParse(ast,text){function attachComments(node){comment.ensureCommentsBefore(text,node)}walk.simple(ast,{VariableDeclaration:attachComments,FunctionDeclaration:attachComments,MethodDefinition:attachComments,Property:attachComments,AssignmentExpression:function(node){"="==node.operator&&attachComments(node)},CallExpression:function(node){isDefinePropertyCall(node)&&attachComments(node)},ExportNamedDeclaration:attachComments,ExportDefaultDeclaration:attachComments,ClassDeclaration:attachComments})}function isDefinePropertyCall(node){return"MemberExpression"==node.callee.type&&"Object"==node.callee.object.name&&"defineProperty"==node.callee.property.name&&node.arguments.length>=3&&"string"==typeof node.arguments[1].value}function postInfer(ast,scope){jsdocParseTypedefs(ast.sourceFile.text,scope),walk.simple(ast,{VariableDeclaration:function(node,scope){var decl=node.declarations[0].id;node.commentsBefore&&"Identifier"==decl.type&&interpretComments(node,node.commentsBefore,scope,scope.getProp(node.declarations[0].id.name))},FunctionDeclaration:function(node,scope){node.commentsBefore&&interpretComments(node,node.commentsBefore,scope,scope.getProp(node.id.name),node.scope.fnType)},ClassDeclaration:function(node,scope){node.commentsBefore&&interpretComments(node,node.commentsBefore,scope,scope.getProp(node.id.name),node.objType)},AssignmentExpression:function(node,scope){node.commentsBefore&&interpretComments(node,node.commentsBefore,scope,infer.expressionType({node:node.left,state:scope}))},ObjectExpression:function(node,scope){for(var i=0;i<node.properties.length;++i){var prop=node.properties[i];if("SpreadElement"!=prop.type){var name=infer.propName(prop);"<i>"!=name&&prop.commentsBefore&&interpretComments(prop,prop.commentsBefore,scope,node.objType.getProp(name))}}},Class:function(node,scope){if(node.objType){var proto=node.objType.getProp("prototype").getObjType();if(proto)for(var i=0;i<node.body.body.length;i++){var method=node.body.body[i],name;method.commentsBefore&&("constructor"==method.kind?interpretComments(method,method.commentsBefore,scope,node.objType):"<i>"!=(name=infer.propName(method))&&interpretComments(method,method.commentsBefore,scope,proto.getProp(name)))}}},CallExpression:function(node,scope){if(node.commentsBefore&&isDefinePropertyCall(node)){var type=infer.expressionType({node:node.arguments[0],state:scope}).getObjType();if(type&&type instanceof infer.Obj){var prop=type.props[node.arguments[1].value];prop&&interpretComments(node,node.commentsBefore,scope,prop)}}},ExportNamedDeclaration:function(node,scope){node.commentsBefore&&node.declaration&&"FunctionDeclaration"===node.declaration.type&&interpretComments(node.declaration,node.commentsBefore,scope,scope.getProp(node.declaration.id.name),node.declaration.scope.fnType)},ExportDefaultDeclaration:function(node,scope){node.commentsBefore&&node.declaration&&"FunctionDeclaration"===node.declaration.type&&interpretComments(node.declaration,node.commentsBefore,scope,scope.getProp(node.declaration.id.name),node.declaration.scope.fnType)}},infer.searchVisitor,scope)}function postLoadDef(data){var defs=data["!typedef"],cx=infer.cx(),orig=data["!name"];if(defs)for(var name in defs)cx.parent.mod.jsdocTypedefs[name]=maybeInstance(infer.def.parse(defs[name],orig,name),name)}function stripLeadingChars(lines){for(var head,i=1;i<lines.length;i++){var line=lines[i],lineHead=line.match(/^[\s\*]*/)[0];if(lineHead!=line)if(null==head)head=lineHead;else{for(var same=0;same<head.length&&head.charCodeAt(same)==lineHead.charCodeAt(same);)++same;same<head.length&&(head=head.slice(0,same))}}for(lines=lines.map(function(line,i){if(line=line.replace(/\s+$/,""),0==i&&null!=head)for(var j=0;j<head.length;j++){var found;if(0==line.indexOf(head.slice(j)))return line.slice(head.length-j)}return null==head||0==i?line.replace(/^[\s\*]*/,""):line.length<head.length?"":line.slice(head.length)});lines.length&&!lines[lines.length-1];)lines.pop();for(;lines.length&&!lines[0];)lines.shift();return lines}function interpretComments(node,comments,scope,aval,type){jsdocInterpretComments(node,scope,aval,comments);var cx=infer.cx();!type&&aval instanceof infer.AVal&&aval.types.length&&((type=aval.types[aval.types.length-1])instanceof infer.Obj&&type.origin==cx.curOrigin&&!type.doc||(type=null));for(var i=comments.length-1;i>=0;i--){var text=stripLeadingChars(comments[i].split(/\r\n?|\n/)).join("\n");if(text){aval instanceof infer.AVal&&(aval.doc=text),type&&(type.doc=text);break}}}function skipSpace(str,pos){for(;/\s/.test(str.charAt(pos));)++pos;return pos}function isIdentifier(string){if(!acorn.isIdentifierStart(string.charCodeAt(0)))return!1;for(var i=1;i<string.length;i++)if(!acorn.isIdentifierChar(string.charCodeAt(i)))return!1;return!0}function parseLabelList(scope,str,pos,close){for(var labels=[],types=[],madeUp=!1,first=!0;pos=skipSpace(str,pos),!first||str.charAt(pos)!=close;first=!1){var colon=str.indexOf(":",pos);if(colon<0)return null;var label=str.slice(pos,colon);if(!isIdentifier(label))return null;labels.push(label);var type=parseType(scope,str,pos=colon+1);if(!type)return null;pos=type.end,madeUp=madeUp||type.madeUp,types.push(type.type),pos=skipSpace(str,pos);var next=str.charAt(pos);if(++pos,next==close)break;if(","!=next)return null}return{labels:labels,types:types,end:pos,madeUp:madeUp}}function parseTypeAtom(scope,str,pos){var result=parseTypeInner(scope,str,pos);return result?"[]"==str.slice(result.end,result.end+2)?{madeUp:result.madeUp,end:result.end+2,type:new infer.Arr(result.type)}:result:null}function parseType(scope,str,pos){for(var type,union=!1,madeUp=!1;;){var inner=parseTypeAtom(scope,str,pos);if(!inner)return null;if(madeUp=madeUp||inner.madeUp,union?inner.type.propagate(union):type=inner.type,pos=skipSpace(str,inner.end),"|"!=str.charAt(pos))break;pos++,union||(union=new infer.AVal,type.propagate(union),type=union)}var isOptional=!1;return"="==str.charAt(pos)&&(++pos,isOptional=!0),{type:type,end:pos,isOptional:isOptional,madeUp:madeUp}}function parseTypeInner(scope,str,pos){pos=skipSpace(str,pos),/[?!]/.test(str.charAt(pos))&&pos++;var type,madeUp=!1;if(str.indexOf("function(",pos)==pos){var args=parseLabelList(scope,str,pos+9,")"),ret=infer.ANull;if(!args)return null;if(pos=skipSpace(str,args.end),":"==str.charAt(pos)){var retType=parseType(scope,str,++pos+1);if(!retType)return null;pos=retType.end,ret=retType.type,madeUp=retType.madeUp}type=new infer.Fn(null,infer.ANull,args.types,args.labels,ret)}else if("["==str.charAt(pos)){var inner;if(!(inner=parseType(scope,str,pos+1)))return null;if(pos=skipSpace(str,inner.end),madeUp=inner.madeUp,"]"!=str.charAt(pos))return null;++pos,type=new infer.Arr(inner.type)}else if("{"==str.charAt(pos)){var fields=parseLabelList(scope,str,pos+1,"}");if(!fields)return null;type=new infer.Obj(!0);for(var i=0;i<fields.types.length;++i){var field=type.defProp(fields.labels[i]);field.initializer=!0,fields.types[i].propagate(field)}pos=fields.end,madeUp=fields.madeUp}else if("("==str.charAt(pos)){var inner;if(!(inner=parseType(scope,str,pos+1)))return null;if(pos=skipSpace(str,inner.end),")"!=str.charAt(pos))return null;++pos,type=inner.type}else{var start=pos;if(!acorn.isIdentifierStart(str.charCodeAt(pos)))return null;for(;acorn.isIdentifierChar(str.charCodeAt(pos));)++pos;if(start==pos)return null;var word=str.slice(start,pos);if(/^(number|integer)$/i.test(word))type=infer.cx().num;else if(/^bool(ean)?$/i.test(word))type=infer.cx().bool;else if(/^string$/i.test(word))type=infer.cx().str;else if(/^(null|undefined)$/i.test(word))type=infer.ANull;else if(/^array$/i.test(word)){var inner=null;if("."==str.charAt(pos)&&"<"==str.charAt(pos+1)){var inAngles=parseType(scope,str,pos+2);if(!inAngles)return null;if(pos=skipSpace(str,inAngles.end),madeUp=inAngles.madeUp,">"!=str.charAt(pos++))return null;inner=inAngles.type}type=new infer.Arr(inner)}else if(/^object$/i.test(word)){if(type=new infer.Obj(!0),"."==str.charAt(pos)&&"<"==str.charAt(pos+1)){var key=parseType(scope,str,pos+2);if(!key)return null;if(pos=skipSpace(str,key.end),","!=str.charAt(pos++))return null;var val=parseType(scope,str,pos);if(!val)return null;if(pos=skipSpace(str,val.end),madeUp=key.madeUp||val.madeUp,">"!=str.charAt(pos++))return null;val.type.propagate(type.defProp("<i>"))}}else{for(;46==str.charCodeAt(pos)||acorn.isIdentifierChar(str.charCodeAt(pos));)++pos;var path=str.slice(start,pos),cx=infer.cx(),defs=cx.parent&&cx.parent.mod.jsdocTypedefs,found;defs&&path in defs?type=defs[path]:(found=infer.def.parsePath(path,scope).getObjType())?type=maybeInstance(found,path):(cx.jsdocPlaceholders||(cx.jsdocPlaceholders=Object.create(null)),type=path in cx.jsdocPlaceholders?cx.jsdocPlaceholders[path]:cx.jsdocPlaceholders[path]=new infer.Obj(null,path),madeUp=!0)}}return{type:type,end:pos,madeUp:madeUp}}function maybeInstance(type,path){if(type instanceof infer.Fn&&/(?:^|\.)[A-Z][^\.]*$/.test(path)){var proto=type.getProp("prototype").getObjType();if(proto instanceof infer.Obj)return infer.getInstance(proto)}return type}function parseTypeOuter(scope,str,pos){if(pos=skipSpace(str,pos||0),"{"!=str.charAt(pos))return null;var result=parseType(scope,str,pos+1);if(!result)return null;var end=skipSpace(str,result.end);return"}"!=str.charAt(end)?null:(result.end=end+1,result)}function jsdocInterpretComments(node,scope,aval,comments){for(var type,args,ret,foundOne,self,parsed,i=0;i<comments.length;++i)for(var comment=comments[i],decl=/(?:\n|\*)\s*@(type|param|arg(?:ument)?|returns?|this|class|constructor)(?:\s*?\n|\s+(.*))/g,m;m=decl.exec(comment);)if("class"!=m[1]&&"constructor"!=m[1]){if(void 0!==m[2])if("this"==m[1]&&(parsed=parseType(scope,m[2],0)))self=parsed,foundOne=!0;else if(parsed=parseTypeOuter(scope,m[2]))switch(foundOne=!0,m[1]){case"returns":case"return":ret=parsed;break;case"type":type=parsed;break;case"param":case"arg":case"argument":var name=m[2].slice(parsed.end).match(/^\s*(\[?)\s*([^\[\]\s=]+(\[\][^\[\]\s=]+)?)\s*(?:=[^\]]+\s*)?(\]?).*/);if(!name)continue;var argname=name[2]+(parsed.isOptional||"["===name[1]&&"]"===name[4]?"?":""),isObjProp=!1,parts=argname.split(".");if(args&&2==parts.length){var objname=parts[0],key,value;for(key in argname=parts[1],args)value=args[key],key===objname&&value.type instanceof infer.Obj?(isObjProp=!0,parsed.type.propagate(value.type.defProp(argname))):key+"[]"===objname&&value.type instanceof infer.Arr&&(isObjProp=!0,parsed.type.propagate(value.type.getProp("<i>").getType().defProp(argname)))}isObjProp||((args||(args=Object.create(null)))[argname]=parsed)}}else self=foundOne=!0;foundOne&&applyType(type,self,args,ret,node,aval)}function jsdocParseTypedefs(text,scope){for(var cx=infer.cx(),re=/\s@typedef\s+(.*)/g,m;m=re.exec(text);){var parsed=parseTypeOuter(scope,m[1]),name=parsed&&m[1].slice(parsed.end).match(/^\s*(\S+)/);if(name&&parsed.type instanceof infer.Obj){for(var rest=text.slice(m.index+m[0].length);m=/\s+@prop(?:erty)?\s+(.*)/.exec(rest);){var propType=parseTypeOuter(scope,m[1]),propName;propType&&(propName=m[1].slice(propType.end).match(/^\s*(\S+)/))&&propType.type.propagate(parsed.type.defProp(propName[1])),rest=rest.slice(m[0].length)}cx.parent.mod.jsdocTypedefs[name[1]]=parsed.type}}}function propagateWithWeight(type,target){var weight=infer.cx().parent.mod.docComment.weight;type.type.propagate(target,weight||(type.madeUp?WG_MADEUP:void 0))}function isFunExpr(node){return"FunctionExpression"==node.type||"ArrowFunctionExpression"==node.type}function applyType(type,self,args,ret,node,aval){var fn;if("VariableDeclaration"==node.type){var decl=node.declarations[0];decl.init&&isFunExpr(decl.init)&&(fn=decl.init.scope.fnType)}else"FunctionDeclaration"==node.type?fn=node.scope.fnType:"AssignmentExpression"==node.type?isFunExpr(node.right)&&(fn=node.right.scope.fnType):"CallExpression"==node.type||"ClassDeclaration"===node.type||isFunExpr(node.value)&&(fn=node.value.scope.fnType);if(fn&&(args||ret||self)){if(args)for(var i=0;i<fn.argNames.length;++i){var name=fn.argNames[i],known=args[name];!known&&(known=args[name+"?"])&&(fn.argNames[i]+="?"),known&&propagateWithWeight(known,fn.args[i])}if(ret&&(fn.retval==infer.ANull&&(fn.retval=new infer.AVal),propagateWithWeight(ret,fn.retval)),!0===self){var proto=fn.getProp("prototype").getObjType();self=proto&&{type:infer.getInstance(proto,fn)}}self&&propagateWithWeight(self,fn.self)}else type&&propagateWithWeight(type,aval)}tern.registerPlugin("doc_comment",function(server,options){server.mod.jsdocTypedefs=Object.create(null),server.on("reset",function(){server.mod.jsdocTypedefs=Object.create(null)}),server.mod.docComment={weight:options&&options.strong?101:void 0,fullDocs:options&&options.fullDocs},server.on("postParse",postParse),server.on("postInfer",postInfer),server.on("postLoadDef",postLoadDef)})});