From a64f80414abf8f3f36d7d06387e3335c06f5d7b0 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 7 Jun 2020 11:02:06 +0800 Subject: [PATCH] Compress CodeMirror --- _server/CodeMirror/LICENSE | 23 + _server/CodeMirror/codeMirror.plugin.js | 44 +- _server/CodeMirror/codeMirror.plugin.min.js | 1 + _server/CodeMirror/tern.js | 4367 ------------------- _server/CodeMirror/tern.min.js | 1 + editor-mobile.html | 4 +- editor.html | 4 +- 7 files changed, 63 insertions(+), 4381 deletions(-) create mode 100644 _server/CodeMirror/codeMirror.plugin.min.js delete mode 100644 _server/CodeMirror/tern.js create mode 100644 _server/CodeMirror/tern.min.js diff --git a/_server/CodeMirror/LICENSE b/_server/CodeMirror/LICENSE index a139012a..2486c559 100644 --- a/_server/CodeMirror/LICENSE +++ b/_server/CodeMirror/LICENSE @@ -32,3 +32,26 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +---------------------------------------------------------------- + +MIT License + +Copyright (C) 2013 by Marijn Haverbeke and others + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/_server/CodeMirror/codeMirror.plugin.js b/_server/CodeMirror/codeMirror.plugin.js index 91ed8624..5b6c65d8 100644 --- a/_server/CodeMirror/codeMirror.plugin.js +++ b/_server/CodeMirror/codeMirror.plugin.js @@ -1051,11 +1051,33 @@ } if (hiding) hiding.style.opacity = 1 findNext(cm, event.shiftKey, function(_, to) { - var dialog - if (to.line < 3 && document.querySelector && - (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && - dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) - (hiding = dialog).style.opacity = .4 + // --- Add count + var text = document.getElementById('CodeMirror-search-count'); + if (text) { + if (to) { + var query = state.query; + if (typeof query === 'string') { + query = new RegExp(query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), queryCaseInsensitive(query) ? "gi": "g"); + } else if (query instanceof RegExp) { + query = new RegExp(query.source, query.flags + "g"); + } else { query = null; } + if (query) { + text.innerText = (cm.getRange({line: 0, ch: 0}, to).match(query) || []).length + + "/" + (cm.getValue().match(query) || []).length; + } else { + text.innerText = '0/0'; + } + } else { + text.innerText = '0/0'; + } + } + if (to) { + var dialog + if (to.line < 3 && document.querySelector && + (dialog = cm.display.wrapper.querySelector(".CodeMirror-dialog")) && + dialog.getBoundingClientRect().bottom - 4 > cm.cursorCoords(to, "window").top) + (hiding = dialog).style.opacity = .4 + } }) }; persistentDialog(cm, getQueryDialog(cm), q, searchNext, function(event, query) { @@ -1091,7 +1113,7 @@ var cursor = getSearchCursor(cm, state.query, rev ? state.posFrom : state.posTo); if (!cursor.find(rev)) { cursor = getSearchCursor(cm, state.query, rev ? CodeMirror.Pos(cm.lastLine()) : CodeMirror.Pos(cm.firstLine(), 0)); - if (!cursor.find(rev)) return; + if (!cursor.find(rev)) return callback && callback(null, null); } cm.setSelection(cursor.from(), cursor.to()); cm.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20); @@ -1100,6 +1122,8 @@ });} function clearSearch(cm) {cm.operation(function() { + var text = document.getElementById('CodeMirror-search-count'); + if (text) text.innerText = ''; var state = getSearchState(cm); state.lastQuery = state.query; if (!state.query) return; @@ -1110,16 +1134,16 @@ function getQueryDialog(cm) { - return '' + "搜索: " + ' ' + "使用/re/语法正则搜索" + ''; + return '搜索: 0/0 使用/re/语法正则搜索'; } function getReplaceQueryDialog(cm) { - return ' ' + "使用/re/语法正则搜索" + ''; + return ' 使用/re/语法正则搜索'; } function getReplacementQueryDialog(cm) { - return '' + "替换为: " + ' '; + return '替换为: '; } function getDoReplaceConfirm(cm) { - return '' + "确认替换?" + ' '; + return '确认替换? '; } function replaceAll(cm, query, text) { diff --git a/_server/CodeMirror/codeMirror.plugin.min.js b/_server/CodeMirror/codeMirror.plugin.min.js new file mode 100644 index 00000000..b1815e9e --- /dev/null +++ b/_server/CodeMirror/codeMirror.plugin.min.js @@ -0,0 +1 @@ +!function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(F){"use strict";var q="CodeMirror-hint-active";function i(e,t){this.cm=e,this.options=t,this.widget=null,this.debounce=0,this.tick=0,this.startPos=this.cm.getCursor("start"),this.startLen=this.cm.getLine(this.startPos.line).length-this.cm.getSelection().length;var n=this;e.on("cursorActivity",this.activityFunc=function(){n.cursorActivity()})}F.showHint=function(e,t,n){if(!t)return e.showHint(n);n&&n.async&&(t.async=!0);var o={hint:t};if(n)for(var i in n)o[i]=n[i];return e.showHint(o)},F.defineExtension("showHint",function(e){e=function(e,t,n){var o=e.options.hintOptions,i={};for(var r in l)i[r]=l[r];if(o)for(var r in o)void 0!==o[r]&&(i[r]=o[r]);if(n)for(var r in n)void 0!==n[r]&&(i[r]=n[r]);i.hint.resolve&&(i.hint=i.hint.resolve(e,t));return i}(this,this.getCursor("start"),e);var t=this.listSelections();if(!(1l.clientHeight+1,H=r.getScrollInfo();0w&&(l.style.width=w-5+"px",E-=O.right-O.left-w),l.style.left=(y=v.left-E-x)+"px"),S)for(var P=l.firstChild;P;P=P.nextSibling)P.style.paddingRight=r.display.nativeBarWidth+"px";return r.addKeyMap(this.keyMap=function(e,o){var i={Up:function(){o.moveFocus(-1)},Down:function(){o.moveFocus(1)},PageUp:function(){o.moveFocus(1-o.menuSize(),!0)},PageDown:function(){o.moveFocus(o.menuSize()-1,!0)},Home:function(){o.setFocus(0)},End:function(){o.setFocus(o.length-1)},Enter:o.pick,Tab:o.pick,Esc:o.close};/Mac/.test(navigator.platform)&&(i["Ctrl-P"]=function(){o.moveFocus(-1)},i["Ctrl-N"]=function(){o.moveFocus(1)});var t=e.options.customKeys,r=t?{}:i;function n(e,t){var n="string"!=typeof t?function(e){return t(e,o)}:i.hasOwnProperty(t)?i[t]:t;r[e]=n}if(t)for(var s in t)t.hasOwnProperty(s)&&n(s,t[s]);var a=e.options.extraKeys;if(a)for(var s in a)a.hasOwnProperty(s)&&n(s,a[s]);return r}(i,{moveFocus:function(e,t){n.changeActive(n.selectedHint+e,t)},setFocus:function(e){n.changeActive(e)},menuSize:function(){return n.screenAmount()},length:o.length,close:function(){i.close()},pick:function(){n.pick()},data:e})),i.options.closeOnUnfocus&&(r.on("blur",this.onBlur=function(){N=setTimeout(function(){i.close()},100)}),r.on("focus",this.onFocus=function(){clearTimeout(N)})),r.on("scroll",this.onScroll=function(){var e=r.getScrollInfo(),t=r.getWrapperElement().getBoundingClientRect(),n=C+H.top-e.top,o=n-(a.pageYOffset||(s.documentElement||s.body).scrollTop);if(b||(o+=l.offsetHeight),o<=t.top||o>=t.bottom)return i.close();l.style.top=n+"px",l.style.left=y+H.left-e.left+"px"}),F.on(l,"dblclick",function(e){var t=D(l,e.target||e.srcElement);t&&null!=t.hintId&&(n.changeActive(t.hintId),n.pick())}),F.on(l,"click",function(e){var t=D(l,e.target||e.srcElement);t&&null!=t.hintId&&(n.changeActive(t.hintId),i.options.completeOnSingleClick&&n.pick())}),F.on(l,"mousedown",function(){setTimeout(function(){r.focus()},20)}),F.signal(e,"select",o[this.selectedHint],l.childNodes[this.selectedHint]),!0}function a(e,t,n,o){var i;e.async?e(t,o,n):(i=e(t,n))&&i.then?i.then(o):o(i)}i.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&F.signal(this.data,"close"),this.widget&&this.widget.close(),F.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(e,t){var n=e.list[t];n.hint?n.hint(this.cm,e,n):this.cm.replaceRange(R(n),n.from||e.from,n.to||e.to,"complete"),F.signal(e,"pick",n),this.close()},cursorActivity:function(){this.debounce&&(r(this.debounce),this.debounce=0);var e,t=this.cm.getCursor(),n=this.cm.getLine(t.line);t.line!=this.startPos.line||n.length-t.ch!=this.startLen-this.startPos.ch||t.ch=this.data.list.length?e=t?this.data.list.length-1:0:e<0&&(e=t?0:this.data.list.length-1),this.selectedHint!=e&&((n=this.hints.childNodes[this.selectedHint])&&(n.className=n.className.replace(" "+q,"")),(n=this.hints.childNodes[this.selectedHint=e]).className+=" "+q,n.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=n.offsetTop+n.offsetHeight-this.hints.clientHeight+3),F.signal(this.data,"select",this.data.list[this.selectedHint],n))},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1}},F.registerHelper("hint","auto",{resolve:function(e,t){var n,s=e.getHelpers(t,"hint");if(s.length){var o=function(e,o,i){var r=function(e,t){if(!e.somethingSelected())return t;for(var n=[],o=0;o,]/,closeOnUnfocus:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null};F.defineOption("hintOptions",null)}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(u){function h(e,t,n){var o=e.getWrapperElement(),i=o.appendChild(document.createElement("div"));return i.className=n?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof t?i.innerHTML=t:i.appendChild(t),u.addClass(o,"dialog-opened"),i}function d(e,t){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=t}u.defineExtension("openDialog",function(e,t,n){n=n||{},d(this,null);var o=h(this,e,n.bottom),i=!1,r=this;function s(e){if("string"==typeof e)l.value=e;else{if(i)return;i=!0,u.rmClass(o.parentNode,"dialog-opened"),o.parentNode.removeChild(o),r.focus(),n.onClose&&n.onClose(o)}}var a,l=o.getElementsByTagName("input")[0];return l?(l.focus(),n.value&&(l.value=n.value,!1!==n.selectValueOnOpen&&l.select()),n.onInput&&u.on(l,"input",function(e){n.onInput(e,l.value,s)}),n.onKeyUp&&u.on(l,"keyup",function(e){n.onKeyUp(e,l.value,s)}),u.on(l,"keydown",function(e){n&&n.onKeyDown&&n.onKeyDown(e,l.value,s)||((27==e.keyCode||!1!==n.closeOnEnter&&13==e.keyCode)&&(l.blur(),u.e_stop(e),s()),13==e.keyCode&&t(l.value,e))}),!1!==n.closeOnBlur&&u.on(l,"blur",s)):(a=o.getElementsByTagName("button")[0])&&(u.on(a,"click",function(){s(),r.focus()}),!1!==n.closeOnBlur&&u.on(a,"blur",s),a.focus()),s}),u.defineExtension("openConfirm",function(e,t,n){d(this,null);var o=h(this,e,n&&n.bottom),i=o.getElementsByTagName("button"),r=!1,s=this,a=1;function l(){r||(r=!0,u.rmClass(o.parentNode,"dialog-opened"),o.parentNode.removeChild(o),s.focus())}i[0].focus();for(var c=0;c>1,a=o(e.slice(0,s)).length;if(a==n)return s;nr.cursorCoords(t,"window").top&&((a=o).style.opacity=.4)}))},i=b(o=r),c=h,f=l,u=function(e,t){var n=d.keyName(e),o=r.getOption("extraKeys"),i=o&&o[n]||d.keyMap[r.getOption("keyMap")][n];"findNext"==i||"findPrev"==i||"findPersistentNext"==i||"findPersistentPrev"==i?(d.e_stop(e),v(r,p(r),t),r.execCommand(i)):"find"!=i&&"findPersistent"!=i||(d.e_stop(e),l(t,e))},o.openDialog(i,f,{value:c,selectValueOnOpen:!0,closeOnEnter:!1,onClose:function(){C(o)},onKeyDown:u}),n&&h&&(v(r,s,h),y(r,t))):m(r,b(),"搜索: ",h,function(e){e&&!s.query&&r.operation(function(){v(r,s,e),s.posFrom=s.posTo=r.getCursor(),y(r,t)})})}function y(n,o,i){n.operation(function(){var e=p(n),t=h(n,e.query,o?e.posFrom:e.posTo);if(!t.find(o)&&!(t=h(n,e.query,o?d.Pos(n.lastLine()):d.Pos(n.firstLine(),0))).find(o))return i&&i(null,null);n.setSelection(t.from(),t.to()),n.scrollIntoView({from:t.from(),to:t.to()},20),e.posFrom=t.from(),e.posTo=t.to(),i&&i(t.from(),t.to())})}function C(n){n.operation(function(){var e=document.getElementById("CodeMirror-search-count");e&&(e.innerText="");var t=p(n);t.lastQuery=t.query,t.query&&(t.query=t.queryText=null,n.removeOverlay(t.overlay),t.annotate&&(t.annotate.clear(),t.annotate=null))})}function b(){return'搜索: 0/0 使用/re/语法正则搜索'}function x(t,o,i){t.operation(function(){for(var n,e=h(t,o);e.findNext();){"string"!=typeof o?(n=t.getRange(e.from(),e.to()).match(o),e.replace(i.replace(/\$(\d)/g,function(e,t){return n[t]}))):e.replace(i)}})}function i(u,e){var t,n;u.getOption("readOnly")||(t=u.getSelection()||p(u).lastQuery,m(u,(n=''+(e?"全部替换":"替换")+"")+' 使用/re/语法正则搜索',n,t,function(f){f&&(f=r(f),m(u,'替换为: ',"替换为: ","",function(s){var a,l,c;s=o(s),e?x(u,f,s):(C(u),a=h(u,f,u.getCursor("from")),l=function(){var e,t,n,o,i,r=a.from();!(e=a.findNext())&&(a=h(u,f),!(e=a.findNext())||r&&a.from().line==r.line&&a.from().ch==r.ch)||(u.setSelection(a.from(),a.to()),u.scrollIntoView({from:a.from(),to:a.to()}),n='确认替换? ',o="确定替换?",i=[function(){c(e)},l,function(){x(u,f,s)}],(t=u).openConfirm?t.openConfirm(n,i):confirm(o)&&i[0]())},c=function(n){a.replace("string"==typeof f?s:s.replace(/\$(\d)/g,function(e,t){return n[t]})),l()},l())}))}))}d.commands.find=function(e){C(e),n(e)},d.commands.findPersistent=function(e){C(e),n(e,!1,!0)},d.commands.findPersistentNext=function(e){n(e,!1,!0,!0)},d.commands.findPersistentPrev=function(e){n(e,!0,!0,!0)},d.commands.findNext=n,d.commands.findPrev=function(e){n(e,!0)},d.commands.clearSearch=C,d.commands.replace=i,d.commands.replaceAll=function(e){i(e,!0)}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(o){var f=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),m=o.Pos,v={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function y(e){return e&&e.bracketRegex||/[(){}[\]]/}function u(e,t,n){var o=e.getLineHandle(t.line),i=t.ch-1,r=n&&n.afterCursor;null==r&&(r=/(^| )cm-fat-cursor($| )/.test(e.getWrapperElement().className));var s=y(n),a=!r&&0<=i&&s.test(o.text.charAt(i))&&v[o.text.charAt(i)]||s.test(o.text.charAt(i+1))&&v[o.text.charAt(++i)];if(!a)return null;var l=">"==a.charAt(1)?1:-1;if(n&&n.strict&&0r))for(f==t.line&&(h=t.ch-(n<0?1:0));h!=d;h+=n){var p=u.charAt(h);if(l.test(p)&&(void 0===o||e.getTokenTypeAt(m(f,h+1))==o)){var g=v[p];if(g&&">"==g.charAt(1)==0",triples:"",explode:"[]{}"},w=k.Pos;function T(e,t){return"pairs"==t&&"string"==typeof e?e:"object"==typeof e&&null!=e[t]?e[t]:n[t]}k.defineOption("autoCloseBrackets",!1,function(e,t,n){n&&n!=k.Init&&(e.removeKeyMap(i),e.state.closeBrackets=null),t&&(o(T(t,"pairs")),e.state.closeBrackets=t,e.addKeyMap(i))});var i={Backspace:function(e){var t=L(e);if(!t||e.getOption("disableInput"))return k.Pass;for(var n=T(t,"pairs"),o=e.listSelections(),i=0;i=r.to&&(r.to=s+1);r.from>n.from.line&&(r.from=n.from.line);t.lineCount()>f&&100 (.*)$/);return{args:e,rettype:o&&o[1]}}(t.type),name:t.exprName||t.name||"fn",guess:t.guess,doc:o.getDoc()},C(n,o,s))})}(this,e)},jumpToDef:function(e){function t(e){var t={type:"definition",variable:e||null},i=u(r,s.getDoc());r.server.request(h(r,i,t),function(e,t){if(e)return T(r,s,e);if(t.file||!t.url){if(t.file){var n,o=r.docs[t.file];if(o&&(n=function(e,t){for(var n=t.context.slice(0,t.contextOffset).split("\n"),o=t.start.line-(n.length-1),i=y(o,(1==n.length?t.start.ch:e.getLine(o).length)-n[0].length),r=e.getLine(o).slice(i.ch),s=1+o;s/g,"\n"))),e.url&&(n.appendChild(document.createTextNode("\n")),(t=n.appendChild(d("a",null,"[文档]"))).href=e.url,t.target="_blank"),n}}function C(e,t,n){L(e);for(var o=e.cachedArgHints,i=o.type,r=d("span",o.guess?p+"fhint-guess":null,d("span",p+"fname",o.name),"("),s=0;s ":")")),i.rettype&&r.appendChild(d("span",p+"type",i.rettype));var l=t.cursorCoords(null,"page"),c=e.activeArgHints=k(l.right+1,l.bottom,r);setTimeout(function(){c.clear=x(t,function(){e.activeArgHints==c&&L(e)})},20)}function l(e,t,n,o,i){n.doc.setSelection(o,i),t!=n&&e.options.switchToDoc&&(L(e),e.options.switchToDoc(n.name,n.doc))}var c=0;function h(e,t,n,o){var i=[],r=0,s=!n.fullDocs;s||delete n.fullDocs,"string"==typeof n&&(n={type:n}),n.lineCharPositions=!0,null==n.end&&(n.end=o||t.doc.getCursor("end"),t.doc.somethingSelected()&&(n.start=t.doc.getCursor("start")));var a=n.start||n.end;for(var l in t.changed?t.doc.lineCount()>f&&!1!=s&&t.changed.to-t.changed.from<100&&t.changed.from<=a.line&&t.changed.to>n.end.line?(i.push(function(e,t,n){for(var o,i=e.doc,r=null,s=null,a=t.line-1,l=Math.max(0,a-50);l<=a;--a){var c=i.getLine(a);c.search(/\bfunction\b/)<0||(u=v.countColumn(c,null,4),null!=r&&r<=u||(r=u,s=a))}null==s&&(s=l);var f=Math.min(i.lastLine(),n.line+20);if(null==r||r==v.countColumn(i.getLine(t.line),null,4))o=f;else for(o=n.line+1;o",n):n(prompt(t,""))}function r(t,e){t.state.ternTooltip&&w(t.state.ternTooltip);var n=t.cursorCoords(),o=t.state.ternTooltip=k(n.right+1,n.bottom,e);var i=!1;v.on(o,"mousemove",function(){i=!0}),v.on(o,"mouseout",function(e){i=!1});var r=x(t,function e(){if(i)return i=!1,void setTimeout(e,100);t.state.ternTooltip=null,o.parentNode&&w(o),r()})}function x(e,t){return e.on("cursorActivity",t),e.on("blur",t),e.on("scroll",t),e.on("setDoc",t),function(){e.off("cursorActivity",t),e.off("blur",t),e.off("scroll",t),e.off("setDoc",t)}}function k(e,t,n){"string"==typeof n&&(n=n.replace(//g,"\n"));var o=d("div",p+"tooltip",n);return o.style.left=e+"px",o.style.top=t+"px",document.body.appendChild(o),o}function w(e){var t=e&&e.parentNode;t&&t.removeChild(e)}function T(e,t,n){e.options.showError?e.options.showError(t,n):r(t,String(n))}function L(e){e.activeArgHints&&(e.activeArgHints.clear&&e.activeArgHints.clear(),w(e.activeArgHints),e.activeArgHints=null)}function M(e,t){var n=t.doc.getValue();return e.options.fileFilter&&(n=e.options.fileFilter(n,t.name,t.doc)),n}function O(t){var n=t.worker=new Worker(t.options.workerScript);n.postMessage({type:"init",defs:t.options.defs,plugins:t.options.plugins,scripts:t.options.workerDeps});var o=0,i={};function r(e,t){t&&(e.id=++o,i[o]=t),n.postMessage(e)}n.onmessage=function(e){var n=e.data;"getFile"==n.type?s(t,n.name,function(e,t){r({type:"getFile",err:String(e),text:t,id:n.id})}):"debug"==n.type?window.console.log(n.message):n.id&&i[n.id]&&(i[n.id](n.err,n.body),delete i[n.id])},n.onerror=function(e){for(var t in i)i[t](e);i={}},this.addFile=function(e,t){r({type:"add",name:e,text:t})},this.delFile=function(e){r({type:"del",name:e})},this.request=function(e,t){r({type:"req",body:e},t)}}}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],e):e(CodeMirror)}(function(h){"use strict";var p="CodeMirror-lint-markers";function d(e){e.parentNode&&e.parentNode.removeChild(e)}function f(e,t,n,o){var i,r,s,a,l=(i=e,r=t,s=n,(a=document.createElement("div")).className="CodeMirror-lint-tooltip cm-s-"+i.options.theme,a.appendChild(s.cloneNode(!0)),i.state.lint.options.selfContain?i.getWrapperElement().appendChild(a):document.body.appendChild(a),h.on(document,"mousemove",c),c(r),null!=a.style.opacity&&(a.style.opacity=1),a);function c(e){if(!a.parentNode)return h.off(document,"mousemove",c);a.style.top=Math.max(0,e.clientY-a.offsetHeight-5)+"px",a.style.left=e.clientX+5+"px"}function f(){var e;h.off(o,"mouseout",f),l&&((e=l).parentNode&&(null==e.style.opacity&&d(e),e.style.opacity=0,setTimeout(function(){d(e)},600)),l=null)}var u=setInterval(function(){if(l)for(var e=o;;e=e.parentNode){if(e&&11==e.nodeType&&(e=e.host),e==document.body)return;if(!e){f();break}}if(!l)return clearInterval(u)},400);h.on(o,"mouseout",f)}function l(t,e,n){this.marked=[],this.options=e,this.timeout=null,this.hasGutter=n,this.onMouseOver=function(e){!function(e,t){var n=t.target||t.srcElement;if(!/\bCodeMirror-lint-mark-/.test(n.className))return;for(var o=n.getBoundingClientRect(),i=(o.left+o.right)/2,r=(o.top+o.bottom)/2,s=e.findMarksAt(e.coordsChar({left:i,top:r},"client")),a=[],l=0;l=t||(s.line>=t&&(s=A(t,0)),t=r.line,null==o?o=this.uncomment(r,s,e)?"un":(this.lineComment(r,s,e),"line"):"un"==o?this.uncomment(r,s,e):this.lineComment(r,s,e))}}),e.defineExtension("lineComment",function(r,e,s){s=s||M;var t,n,a,l,c,f,u=this,o=S(u,r),i=u.getLine(r.line);null!=i&&(t=r,n=i,!/\bstring\b/.test(u.getTokenTypeAt(A(t.line,0)))||/^[\'\"\`]/.test(n))&&((a=s.lineComment||o.lineComment)?(l=Math.min(0!=e.ch||e.line==r.line?e.line+1:e.line,u.lastLine()+1),c=null==s.padding?" ":s.padding,f=s.commentBlankLines||r.line==e.line,u.operation(function(){if(s.indent){for(var e=null,t=r.line;tn.length)&&(e=n)}for(t=r.line;ts||l.operation(function(){if(0!=r.fullLines){var e=O.test(l.getLine(s));l.replaceRange(a+u,A(s)),l.replaceRange(f+a,A(o.line,0));var t=r.blockCommentLead||c.blockCommentLead;if(null!=t)for(var n=o.line+1;n<=s;++n)n==s&&!e||l.replaceRange(t+a,A(n,0))}else l.replaceRange(u,i),l.replaceRange(f,o)})):(r.lineComment||c.lineComment)&&0!=r.fullLines&&l.lineComment(o,i,r)}),e.defineExtension("uncomment",function(e,t,n){n=n||M;var i,r=this,o=S(r,e),s=Math.min(0!=t.ch||t.line==e.line?t.line:t.line-1,r.lastLine()),a=Math.min(e.line,s),l=n.lineComment||o.lineComment,c=[],f=null==n.padding?" ":n.padding;e:if(l){for(var u=a;u<=s;++u){var h=r.getLine(u),d=h.indexOf(l);if(-1i.firstLine();)r=f.Pos(r.line-1,0),c=t(!1);c&&!c.cleared&&"unfold"!==s&&(n=function(e,t,n){var o=u(e,t,"widget");"function"==typeof o&&(o=o(n.from,n.to));{var i;"string"==typeof o?(i=document.createTextNode(o),(o=document.createElement("span")).appendChild(i),o.className="CodeMirror-foldmarker"):o=o&&o.cloneNode(!0)}return o}(i,e,c),f.on(n,"mousedown",function(e){o.clear(),f.e_preventDefault(e)}),(o=i.markText(c.from,c.to,{replacedWith:n,clearOnEnter:u(i,e,"clearOnEnter"),__isFold:!0})).on("clear",function(e,t){f.signal(i,"unfold",i,e,t)}),f.signal(i,"fold",i,c.from,c.to))}f.newFoldFunction=function(n,o){return function(e,t){i(e,t,{rangeFinder:n,widget:o})}},f.defineExtension("foldCode",function(e,t,n){i(this,e,t,n)}),f.defineExtension("isFolded",function(e){for(var t=this.findMarksAt(e),n=0;n=l){if(u&&n&&u.test(n.className))return;t=p(s.indicatorOpen)}}(t||n)&&r.setGutterMarker(e,s.gutter,t)})}function n(e){return new RegExp("(^|\\s)"+e+"(?:$|\\s)\\s*")}function s(e){var t=e.getViewport(),n=e.state.foldGutter;n&&(e.operation(function(){r(e,t.from,t.to)}),n.from=t.from,n.to=t.to)}function a(e,t,n){var o,i,r=e.state.foldGutter;!r||n==(o=r.options).gutter&&((i=d(e,t))?i.clear():e.foldCode(h(t,0),o))}function l(e){var t,n=e.state.foldGutter;n&&(t=n.options,n.from=n.to=0,clearTimeout(n.changeUpdate),n.changeUpdate=setTimeout(function(){s(e)},t.foldOnChangeTimeSpan||600))}function c(t){var e,n=t.state.foldGutter;n&&(e=n.options,clearTimeout(n.changeUpdate),n.changeUpdate=setTimeout(function(){var e=t.getViewport();n.from==n.to||20n.to&&(r(t,n.to,e.to),n.to=e.to)})},e.updateViewportTimeSpan||400))}function f(e,t){var n,o=e.state.foldGutter;!o||(n=t.line)>=o.from&&nr.lastLine())return null;var t=r.getTokenAt(y.Pos(e,1));if(/\S/.test(t.string)||(t=r.getTokenAt(y.Pos(e,t.end+1))),"keyword"!=t.type||"import"!=t.string)return null;for(var n=e,o=Math.min(r.lastLine(),e+10);n<=o;++n){var i=r.getLine(n).indexOf(";");if(-1!=i)return{startCh:t.end,end:y.Pos(n,i)}}}var n,o=e.line,i=t(o);if(!i||t(o-1)||(n=t(o-2))&&n.end.line==o-1)return null;for(var s=i.end;;){var a=t(s.line+1);if(null==a)break;s=a.end}return{from:r.clipPos(y.Pos(o,i.startCh+1)),to:s}}),y.registerHelper("fold","include",function(n,e){function t(e){if(en.lastLine())return null;var t=n.getTokenAt(y.Pos(e,1));return/\S/.test(t.string)||(t=n.getTokenAt(y.Pos(e,t.end+1))),"meta"==t.type&&"#include"==t.string.slice(0,8)?t.start+8:void 0}var o=e.line,i=t(o);if(null==i||null!=t(o-1))return null;for(var r=o;;){if(null==t(r+1))break;++r}return{from:y.Pos(o,i+1),to:n.clipPos(y.Pos(r))}})}),function(e){"object"==typeof exports&&"object"==typeof module?e(require("../../lib/codemirror"),require("./matchesonscrollbar")):"function"==typeof define&&define.amd?define(["../../lib/codemirror","./matchesonscrollbar"],e):e(CodeMirror)}(function(i){"use strict";var n={style:"matchhighlight",minChars:2,delay:100,wordsOnly:!1,annotateScrollbar:!1,showToken:!1,trim:!0};function r(e){for(var t in this.options={},n)this.options[t]=(e&&e.hasOwnProperty(t)?e:n)[t];this.overlay=this.timeout=null,this.matchesonscroll=null,this.active=!1}function s(e){var t=e.state.matchHighlighter;(t.active||e.hasFocus())&&o(e,t)}function a(e){var t=e.state.matchHighlighter;t.active||(t.active=!0,o(e,t))}function o(e,t){clearTimeout(t.timeout),t.timeout=setTimeout(function(){l(e)},t.options.delay)}function f(e,t,n,o){var i,r,s,a,l=e.state.matchHighlighter;e.addOverlay(l.overlay=(i=t,r=n,s=o,{token:function(e){if(e.match(i)&&(!r||(n=r,!((t=e).start&&n.test(t.string.charAt(t.start-1))||t.pos!=t.string.length&&n.test(t.string.charAt(t.pos))))))return s;var t,n;e.next(),e.skipTo(i.charAt(0))||e.skipToEnd()}})),l.options.annotateScrollbar&&e.showMatchesOnScrollbar&&(a=n?new RegExp((/\w/.test(t.charAt(0))?"\\b":"")+t.replace(/[\\\[.+*?(){|^$]/g,"\\$&")+(/\w/.test(t.charAt(t.length-1))?"\\b":"")):t,l.matchesonscroll=e.showMatchesOnScrollbar(a,!1,{className:"CodeMirror-selection-highlight-scrollbar"}))}function u(e){var t=e.state.matchHighlighter;t.overlay&&(e.removeOverlay(t.overlay),t.overlay=null,t.matchesonscroll&&(t.matchesonscroll.clear(),t.matchesonscroll=null))}function l(c){c.operation(function(){var e=c.state.matchHighlighter;if(u(c),c.somethingSelected()||!e.options.showToken){var t,n=c.getCursor("from"),o=c.getCursor("to");n.line==o.line&&(e.options.wordsOnly&&!function(e,t,n){{if(null===e.getRange(t,n).match(/^\w+$/))return;if(0=e.options.minChars&&f(c,t,!1,e.options.style)))}else{for(var i=!0===e.options.showToken?/[\w$]/:e.options.showToken,r=c.getCursor(),s=c.getLine(r.line),a=r.ch,l=a;a&&i.test(s.charAt(a-1));)--a;for(;l 0 && arr; - } - - exports.mixin = function(obj) { - obj.on = on; obj.off = off; - obj.signal = signal; - obj.signalReturnFirst = signalReturnFirst; - obj.hasHandler = hasHandler; - return obj; - }; -}); -// The Tern server object - -// A server is a stateful object that manages the analysis for a -// project, and defines an interface for querying the code in the -// project. - -(function(root, mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - return mod(exports, require("./infer"), require("./signal"), - require("acorn"), require("acorn-walk")); - if (typeof define == "function" && define.amd) // AMD - return define(["exports", "./infer", "./signal", "acorn/dist/acorn", "acorn-walk/dist/walk"], mod); - mod(root.tern || (root.tern = {}), tern, tern.signal, acorn, acorn.walk); // Plain browser env -})(this, function(exports, infer, signal, acorn, walk) { - "use strict"; - - var plugins = Object.create(null); - exports.registerPlugin = function(name, init) { plugins[name] = init; }; - - var defaultOptions = exports.defaultOptions = { - debug: false, - async: false, - getFile: function(_f, c) { if (this.async) c(null, null); }, - normalizeFilename: function(name) { return name }, - defs: [], - plugins: {}, - fetchTimeout: 1000, - dependencyBudget: 20000, - reuseInstances: true, - stripCRs: false, - ecmaVersion: 9, - projectDir: "/", - parent: null - }; - - var queryTypes = { - completions: { - takesFile: true, - run: findCompletions - }, - properties: { - run: findProperties - }, - type: { - takesFile: true, - run: findTypeAt - }, - documentation: { - takesFile: true, - run: findDocs - }, - definition: { - takesFile: true, - run: findDef - }, - refs: { - takesFile: true, - fullFile: true, - run: findRefs - }, - rename: { - takesFile: true, - fullFile: true, - run: buildRename - }, - files: { - run: listFiles - } - }; - - exports.defineQueryType = function(name, desc) { queryTypes[name] = desc; }; - - function File(name, parent) { - this.name = name; - this.parent = parent; - this.scope = this.text = this.ast = this.lineOffsets = null; - } - File.prototype.asLineChar = function(pos) { return asLineChar(this, pos); }; - - function parseFile(srv, file) { - var options = { - directSourceFile: file, - allowReturnOutsideFunction: true, - allowImportExportEverywhere: true, - ecmaVersion: srv.options.ecmaVersion, - allowHashBang: true - }; - var text = srv.signalReturnFirst("preParse", file.text, options) || file.text; - var ast = infer.parse(text, options); - srv.signal("postParse", ast, text); - return ast; - } - - var astral = /[\uD800-\uDBFF]/g; - - function updateText(file, text, srv) { - file.text = srv.options.stripCRs ? text.replace(/\r\n/g, "\n") : text; - file.hasAstral = astral.test(file.text); - infer.withContext(srv.cx, function() { - file.ast = parseFile(srv, file); - }); - file.lineOffsets = null; - } - - var Server = exports.Server = function(options) { - this.cx = null; - this.options = options || {}; - for (var o in defaultOptions) if (!options.hasOwnProperty(o)) - options[o] = defaultOptions[o]; - - this.projectDir = options.projectDir.replace(/\\/g, "/"); - if (!/\/$/.test(this.projectDir)) this.projectDir += "/"; - - this.parent = options.parent; - this.handlers = Object.create(null); - this.files = []; - this.fileMap = Object.create(null); - this.needsPurge = []; - this.budgets = Object.create(null); - this.uses = 0; - this.pending = 0; - this.asyncError = null; - this.mod = {}; - - this.defs = options.defs.slice(0); - this.plugins = Object.create(null); - for (var plugin in options.plugins) if (options.plugins.hasOwnProperty(plugin)) - this.loadPlugin(plugin, options.plugins[plugin]); - - this.reset(); - }; - Server.prototype = signal.mixin({ - addFile: function(name, /*optional*/ text, parent) { - // Don't crash when sloppy plugins pass non-existent parent ids - if (parent && !(parent in this.fileMap)) parent = null; - if (!(name in this.fileMap)) - name = this.normalizeFilename(name); - ensureFile(this, name, parent, text); - }, - delFile: function(name) { - var file = this.findFile(name); - if (file) { - this.needsPurge.push(file.name); - for (var i = 0; i < this.files.length; i++) { - if (this.files[i] == file) this.files.splice(i--, 1); - else if (this.files[i].parent == name) this.files[i].parent = null; - } - delete this.fileMap[file.name]; - } - }, - reset: function() { - this.signal("reset"); - this.cx = new infer.Context(this.defs, this); - this.uses = 0; - this.budgets = Object.create(null); - for (var i = 0; i < this.files.length; ++i) { - var file = this.files[i]; - if (file.scope) { - infer.clearScopes(file.ast); - file.scope = null; - } - } - this.signal("postReset"); - }, - - request: function(doc, c) { - var inv = invalidDoc(doc); - if (inv) return c(inv); - - var self = this; - doRequest(this, doc, function(err, data) { - c(err, data); - if (self.uses > 40) { - self.reset(); - analyzeAll(self, null, function(){}); - } - }); - }, - - findFile: function(name) { - return this.fileMap[this.normalizeFilename(name)]; - }, - - flush: function(c) { - var cx = this.cx; - analyzeAll(this, null, function(err) { - if (err) return c(err); - infer.withContext(cx, c); - }); - }, - - startAsyncAction: function() { - ++this.pending; - }, - finishAsyncAction: function(err) { - if (err) this.asyncError = err; - if (--this.pending === 0) this.signal("everythingFetched"); - }, - - addDefs: function(defs, toFront) { - if (toFront) this.defs.unshift(defs); - else this.defs.push(defs); - - if (this.cx) this.reset(); - }, - - deleteDefs: function(name) { - for (var i = 0; i < this.defs.length; i++) if (this.defs[i]["!name"] == name) { - this.defs.splice(i, 1); - if (this.cx) this.reset(); - return; - } - }, - - loadPlugin: function(name, options) { - if (arguments.length == 1) options = this.options.plugins[name] || true; - if (name in this.plugins || !(name in plugins) || !options) return; - this.plugins[name] = true; - var init = plugins[name](this, options); - - // This is for backwards-compatibilty. Don't rely on it -- use addDef and on directly - if (!init) return; - if (init.defs) this.addDefs(init.defs, init.loadFirst); - if (init.passes) for (var type in init.passes) if (init.passes.hasOwnProperty(type)) - this.on(type, init.passes[type]); - }, - - normalizeFilename: function(name) { - var norm = this.options.normalizeFilename(name).replace(/\\/g, "/"); - if (norm.indexOf(this.projectDir) == 0) norm = norm.slice(this.projectDir.length); - return norm; - } - }); - - function doRequest(srv, doc, c) { - if (doc.query && !queryTypes.hasOwnProperty(doc.query.type)) - return c("No query type '" + doc.query.type + "' defined"); - - var query = doc.query; - // Respond as soon as possible when this just uploads files - if (!query) c(null, {}); - - var files = doc.files || []; - if (files.length) ++srv.uses; - for (var i = 0; i < files.length; ++i) { - var file = files[i]; - file.name = srv.normalizeFilename(file.name); - if (file.type == "delete") - srv.delFile(file.name); - else - ensureFile(srv, file.name, null, file.type == "full" ? file.text : null); - } - - var timeBudget = typeof doc.timeout == "number" ? [doc.timeout] : null; - if (!query) { - analyzeAll(srv, timeBudget, function(){}); - return; - } - - var queryType = queryTypes[query.type]; - if (queryType.takesFile) { - if (typeof query.file != "string") return c(".query.file must be a string"); - if (!/^#/.test(query.file)) ensureFile(srv, query.file, null); - } - - analyzeAll(srv, timeBudget, function(err) { - if (err) return c(err); - var file = queryType.takesFile && resolveFile(srv, files, query.file); - if (queryType.fullFile && file.type == "part") - return c("Can't run a " + query.type + " query on a file fragment"); - - infer.resetGuessing(); - infer.withContext(srv.cx, function() { - var result, run = function() { result = queryType.run(srv, query, file); }; - try { - if (timeBudget) infer.withTimeout(timeBudget[0], run); - else run(); - } catch (e) { - if (srv.options.debug && e.name != "TernError") console.error(e.stack); - return c(e); - } - c(null, result); - }); - }); - } - - function analyzeFile(srv, file) { - infer.withContext(srv.cx, function() { - file.scope = srv.cx.topScope; - srv.signal("beforeLoad", file); - infer.analyze(file.ast, file.name, file.scope); - srv.signal("afterLoad", file); - }); - return file; - } - - function ensureFile(srv, name, parent, text) { - var known = srv.findFile(name); - if (known) { - if (text != null) { - if (known.scope) { - srv.needsPurge.push(name); - infer.clearScopes(known.ast); - known.scope = null; - } - updateText(known, text, srv); - } - if (parentDepth(srv, known.parent) > parentDepth(srv, parent)) { - known.parent = parent; - if (known.excluded) known.excluded = null; - } - return; - } - - var file = new File(name, parent); - srv.files.push(file); - srv.fileMap[name] = file; - if (text != null) { - updateText(file, text, srv); - } else if (srv.options.async) { - srv.startAsyncAction(); - srv.options.getFile(name, function(err, text) { - updateText(file, text || "", srv); - srv.finishAsyncAction(err); - }); - } else { - updateText(file, srv.options.getFile(name) || "", srv); - } - } - - function fetchAll(srv, c) { - var done = true, returned = false; - srv.files.forEach(function(file) { - if (file.text != null) return; - if (srv.options.async) { - done = false; - srv.options.getFile(file.name, function(err, text) { - if (err && !returned) { returned = true; return c(err); } - updateText(file, text || "", srv); - fetchAll(srv, c); - }); - } else { - try { - updateText(file, srv.options.getFile(file.name) || "", srv); - } catch (e) { return c(e); } - } - }); - if (done) c(); - } - - function waitOnFetch(srv, timeBudget, c) { - var done = function() { - srv.off("everythingFetched", done); - clearTimeout(timeout); - analyzeAll(srv, timeBudget, c); - }; - srv.on("everythingFetched", done); - var timeout = setTimeout(done, srv.options.fetchTimeout); - } - - function analyzeAll(srv, timeBudget, c) { - if (srv.pending) return waitOnFetch(srv, timeBudget, c); - - var e = srv.fetchError; - if (e) { srv.fetchError = null; return c(e); } - - if (srv.needsPurge.length > 0) infer.withContext(srv.cx, function() { - infer.purge(srv.needsPurge); - srv.needsPurge.length = 0; - }); - - var done = true; - // The second inner loop might add new files. The outer loop keeps - // repeating both inner loops until all files have been looked at. - for (var i = 0; i < srv.files.length;) { - var toAnalyze = []; - for (; i < srv.files.length; ++i) { - var file = srv.files[i]; - if (file.text == null) done = false; - else if (file.scope == null && !file.excluded) toAnalyze.push(file); - } - toAnalyze.sort(function(a, b) { - return parentDepth(srv, a.parent) - parentDepth(srv, b.parent); - }); - for (var j = 0; j < toAnalyze.length; j++) { - var file = toAnalyze[j]; - if (file.parent && !chargeOnBudget(srv, file)) { - file.excluded = true; - } else if (timeBudget) { - var startTime = +new Date; - try { - infer.withTimeout(timeBudget[0], function() { analyzeFile(srv, file); }); - } catch(e) { - if (e instanceof infer.TimedOut) return c(e); - else throw e; - } - timeBudget[0] -= +new Date - startTime; - } else { - analyzeFile(srv, file); - } - } - } - if (done) c(); - else waitOnFetch(srv, timeBudget, c); - } - - function firstLine(str) { - var end = str.indexOf("\n"); - if (end < 0) return str; - return str.slice(0, end); - } - - function findMatchingPosition(line, file, near) { - var pos = Math.max(0, near - 500), closest = null; - if (!/^\s*$/.test(line)) for (;;) { - var found = file.indexOf(line, pos); - if (found < 0 || found > near + 500) break; - if (closest == null || Math.abs(closest - near) > Math.abs(found - near)) - closest = found; - pos = found + line.length; - } - return closest; - } - - function scopeDepth(s) { - for (var i = 0; s; ++i, s = s.prev) {} - return i; - } - - function ternError(msg) { - var err = new Error(msg); - err.name = "TernError"; - return err; - } - - function resolveFile(srv, localFiles, name) { - var isRef = name.match(/^#(\d+)$/); - if (!isRef) return srv.findFile(name); - - var file = localFiles[isRef[1]]; - if (!file || file.type == "delete") throw ternError("Reference to unknown file " + name); - if (file.type == "full") return srv.fileMap[file.name]; - - // This is a partial file - - var realFile = file.backing = srv.fileMap[file.name]; - var offset = resolvePos(realFile, file.offsetLines == null ? file.offset : {line: file.offsetLines, ch: 0}, true); - var line = firstLine(file.text); - var foundPos = findMatchingPosition(line, realFile.text, offset); - var pos = foundPos == null ? Math.max(0, realFile.text.lastIndexOf("\n", offset)) : foundPos; - var inObject, atFunction; - - infer.withContext(srv.cx, function() { - infer.purge(file.name, pos, pos + file.text.length); - - var text = file.text, m; - if (m = text.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/)) { - var objNode = walk.findNodeAround(file.backing.ast, pos, "ObjectExpression"); - if (objNode && objNode.node.objType) - inObject = {type: objNode.node.objType, prop: m[2] || m[1]}; - } - if (foundPos && (m = line.match(/^(.*?)\bfunction\b/))) { - var cut = m[1].length, white = ""; - for (var i = 0; i < cut; ++i) white += " "; - file.text = white + text.slice(cut); - atFunction = true; - } - - var scopeStart = infer.scopeAt(realFile.ast, pos, realFile.scope); - var scopeEnd = infer.scopeAt(realFile.ast, pos + text.length, realFile.scope); - var scope = file.scope = scopeDepth(scopeStart) < scopeDepth(scopeEnd) ? scopeEnd : scopeStart; - file.ast = parseFile(srv, file); - infer.analyze(file.ast, file.name, scope); - - // This is a kludge to tie together the function types (if any) - // outside and inside of the fragment, so that arguments and - // return values have some information known about them. - tieTogether: { - if (inObject || atFunction) { - var newInner = infer.scopeAt(file.ast, line.length, scopeStart); - if (!newInner.fnType) break tieTogether; - if (inObject) { - var prop = inObject.type.getProp(inObject.prop); - prop.addType(newInner.fnType); - } else if (atFunction) { - var inner = infer.scopeAt(realFile.ast, pos + line.length, realFile.scope); - if (inner == scopeStart || !inner.fnType) break tieTogether; - var fOld = inner.fnType, fNew = newInner.fnType; - if (!fNew || (fNew.name != fOld.name && fOld.name)) break tieTogether; - for (var i = 0, e = Math.min(fOld.args.length, fNew.args.length); i < e; ++i) - fOld.args[i].propagate(fNew.args[i]); - fOld.self.propagate(fNew.self); - fNew.retval.propagate(fOld.retval); - } - } - } - }); - return file; - } - - // Budget management - - function astSize(node) { - var size = 0; - walk.simple(node, {Expression: function() { ++size; }}); - return size; - } - - function parentDepth(srv, parent) { - var depth = 0; - while (parent) { - parent = srv.fileMap[parent].parent; - ++depth; - } - return depth; - } - - function budgetName(srv, file) { - for (;;) { - var parent = srv.fileMap[file.parent]; - if (!parent.parent) break; - file = parent; - } - return file.name; - } - - function chargeOnBudget(srv, file) { - var bName = budgetName(srv, file); - var size = astSize(file.ast); - var known = srv.budgets[bName]; - if (known == null) - known = srv.budgets[bName] = srv.options.dependencyBudget; - if (known < size) return false; - srv.budgets[bName] = known - size; - return true; - } - - // Query helpers - - function isPosition(val) { - return typeof val == "number" || typeof val == "object" && - typeof val.line == "number" && typeof val.ch == "number"; - } - - // Baseline query document validation - function invalidDoc(doc) { - if (doc.query) { - if (typeof doc.query.type != "string") return ".query.type must be a string"; - if (doc.query.start && !isPosition(doc.query.start)) return ".query.start must be a position"; - if (doc.query.end && !isPosition(doc.query.end)) return ".query.end must be a position"; - } - if (doc.files) { - if (!Array.isArray(doc.files)) return "Files property must be an array"; - for (var i = 0; i < doc.files.length; ++i) { - var file = doc.files[i]; - if (typeof file != "object") return ".files[n] must be objects"; - else if (typeof file.name != "string") return ".files[n].name must be a string"; - else if (file.type == "delete") continue; - else if (typeof file.text != "string") return ".files[n].text must be a string"; - else if (file.type == "part") { - if (!isPosition(file.offset) && typeof file.offsetLines != "number") - return ".files[n].offset must be a position"; - } else if (file.type != "full") return ".files[n].type must be \"full\" or \"part\""; - } - } - } - - var offsetSkipLines = 25; - - function forwardCharacters(file, start, chars) { - var pos = start + chars, m; - if (file.hasAstral) { - astral.lastIndex = start; - while ((m = astral.exec(file.text)) && m.index < pos) pos++; - } - return pos; - } - - function findLineStart(file, line) { - var text = file.text, offsets = file.lineOffsets || (file.lineOffsets = [0]); - var pos = 0, curLine = 0; - var storePos = Math.min(Math.floor(line / offsetSkipLines), offsets.length - 1); - var pos = offsets[storePos], curLine = storePos * offsetSkipLines; - - while (curLine < line) { - ++curLine; - pos = text.indexOf("\n", pos) + 1; - if (pos === 0) return null; - if (curLine % offsetSkipLines === 0) offsets.push(pos); - } - return pos; - } - - var resolvePos = exports.resolvePos = function(file, pos, tolerant) { - if (typeof pos != "number") { - var lineStart = findLineStart(file, pos.line); - if (lineStart == null) { - if (tolerant) pos = file.text.length; - else throw ternError("File doesn't contain a line " + pos.line); - } else { - pos = forwardCharacters(file, lineStart, pos.ch); - } - } else { - pos = forwardCharacters(file, 0, pos); - } - if (pos > file.text.length) { - if (tolerant) pos = file.text.length; - else throw ternError("Position " + pos + " is outside of file."); - } - return pos; - }; - - function charDistanceBetween(file, start, end) { - var diff = end - start, m; - if (file.hasAstral) { - astral.lastIndex = start; - while ((m = astral.exec(file.text)) && m.index < end) diff--; - } - return diff; - } - - function asLineChar(file, pos) { - if (!file) return {line: 0, ch: 0}; - var offsets = file.lineOffsets || (file.lineOffsets = [0]); - var text = file.text, line, lineStart; - for (var i = offsets.length - 1; i >= 0; --i) if (offsets[i] <= pos) { - line = i * offsetSkipLines; - lineStart = offsets[i]; - } - for (;;) { - var eol = text.indexOf("\n", lineStart); - if (eol >= pos || eol < 0) break; - lineStart = eol + 1; - ++line; - } - return {line: line, ch: charDistanceBetween(file, lineStart, pos)}; - } - - var outputPos = exports.outputPos = function(query, file, pos) { - if (query.lineCharPositions) { - var out = asLineChar(file, pos); - if (file.type == "part") - out.line += file.offsetLines != null ? file.offsetLines : asLineChar(file.backing, file.offset).line; - return out; - } else { - return charDistanceBetween(file, 0, pos) + (file.type == "part" ? file.offset : 0); - } - }; - - // Delete empty fields from result objects - function clean(obj) { - for (var prop in obj) if (obj[prop] == null) delete obj[prop]; - return obj; - } - function maybeSet(obj, prop, val) { - if (val != null) obj[prop] = val; - } - - // Built-in query types - - function compareCompletions(a, b) { - if (typeof a != "string") { a = a.name; b = b.name; } - var aUp = /^[A-Z]/.test(a), bUp = /^[A-Z]/.test(b); - if (aUp == bUp) return a < b ? -1 : a == b ? 0 : 1; - else return aUp ? 1 : -1; - } - - function isStringAround(node, start, end) { - return node.type == "Literal" && typeof node.value == "string" && - node.start == start - 1 && node.end <= end + 1; - } - - function pointInProp(objNode, point) { - for (var i = 0; i < objNode.properties.length; i++) { - var curProp = objNode.properties[i]; - if (curProp.key.start <= point && curProp.key.end >= point) - return curProp; - } - } - - var jsKeywords = ("break do instanceof typeof case else new var " + - "catch finally return void continue for switch while debugger " + - "function this with default if throw delete in try").split(" "); - var jsKeywordsES6 = jsKeywords.concat("export class extends const super yield import let static".split(" ")); - - var addCompletion = exports.addCompletion = function(query, completions, name, aval, depth) { - var typeInfo = query.types || query.docs || query.urls || query.origins; - var wrapAsObjs = typeInfo || query.depths; - - for (var i = 0; i < completions.length; ++i) { - var c = completions[i]; - if ((wrapAsObjs ? c.name : c) == name) return; - } - var rec = wrapAsObjs ? {name: name} : name; - completions.push(rec); - - if (aval && typeInfo) { - infer.resetGuessing(); - var type = aval.getType(); - rec.guess = infer.didGuess(); - if (query.types) - rec.type = infer.toString(aval); - if (query.docs) - maybeSet(rec, "doc", parseDoc(query, aval.doc || type && type.doc)); - if (query.urls) - maybeSet(rec, "url", aval.url || type && type.url); - if (query.origins) - maybeSet(rec, "origin", aval.origin || type && type.origin); - } - if (query.depths) rec.depth = depth || 0; - return rec; - }; - - function findCompletions(srv, query, file) { - if (query.end == null) throw ternError("missing .query.end field"); - var fromPlugin = srv.signalReturnFirst("completion", file, query); - if (fromPlugin) return fromPlugin; - - var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text; - while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1))) --wordStart; - if (query.expandWordForward !== false) - while (wordEnd < text.length && acorn.isIdentifierChar(text.charCodeAt(wordEnd))) ++wordEnd; - var word = text.slice(wordStart, wordEnd), completions = [], ignoreObj; - if (query.caseInsensitive) word = word.toLowerCase(); - - function gather(prop, obj, depth, addInfo) { - // 'hasOwnProperty' and such are usually just noise, leave them - // out when no prefix is provided. - if ((objLit || query.omitObjectPrototype !== false) && obj == srv.cx.protos.Object && !word) return; - if (query.filter !== false && word && - (query.caseInsensitive ? prop.toLowerCase() : prop).indexOf(word) !== 0) return; - if (ignoreObj && ignoreObj.props[prop]) return; - var result = addCompletion(query, completions, prop, obj && obj.props[prop], depth); - if (addInfo && result && typeof result != "string") addInfo(result); - } - - var hookname, prop, objType, isKey; - - var exprAt = infer.findExpressionAround(file.ast, null, wordStart, file.scope); - var memberExpr, objLit; - // Decide whether this is an object property, either in a member - // expression or an object literal. - if (exprAt) { - var exprNode = exprAt.node; - - if (query.inLiteral === false && exprNode.type === "Literal" && - (typeof exprNode.value === 'string' || exprNode.regex)) - return { - start: outputPos(query, file, wordStart), - end: outputPos(query, file, wordEnd), - completions: [] - }; - - if (exprNode.type == "MemberExpression" && exprNode.object.end < wordStart) { - memberExpr = exprAt; - } else if (isStringAround(exprNode, wordStart, wordEnd)) { - var parent = infer.parentNode(exprNode, file.ast); - if (parent.type == "MemberExpression" && parent.property == exprNode) - memberExpr = {node: parent, state: exprAt.state}; - } else if (exprNode.type == "ObjectExpression") { - var objProp = pointInProp(exprNode, wordEnd); - if (objProp) { - objLit = exprAt; - prop = isKey = objProp.key.name || objProp.key.value; - } else if (!word && !/:\s*$/.test(file.text.slice(0, wordStart))) { - objLit = exprAt; - prop = isKey = true; - } - } - } - - if (objLit) { - // Since we can't use the type of the literal itself to complete - // its properties (it doesn't contain the information we need), - // we have to try asking the surrounding expression for type info. - objType = infer.typeFromContext(file.ast, objLit); - ignoreObj = objLit.node.objType; - } else if (memberExpr) { - prop = memberExpr.node.property; - prop = prop.type == "Literal" ? prop.value.slice(1) : prop.name; - memberExpr.node = memberExpr.node.object; - objType = infer.expressionType(memberExpr); - } else if (text.charAt(wordStart - 1) == ".") { - var pathStart = wordStart - 1; - while (pathStart && (text.charAt(pathStart - 1) == "." || acorn.isIdentifierChar(text.charCodeAt(pathStart - 1)))) pathStart--; - var path = text.slice(pathStart, wordStart - 1); - if (path) { - objType = infer.def.parsePath(path, file.scope).getObjType(); - prop = word; - } - } - - if (prop != null) { - srv.cx.completingProperty = prop; - - if (objType) infer.forAllPropertiesOf(objType, gather); - - if (!completions.length && query.guess !== false && objType && objType.guessProperties) - objType.guessProperties(function(p, o, d) {if (p != prop && p != "✖" && p != "") gather(p, o, d);}); - if (!completions.length && word.length >= 2 && query.guess !== false) - for (var prop in srv.cx.props) gather(prop, srv.cx.props[prop][0], 0); - hookname = "memberCompletion"; - } else { - infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather); - if (query.includeKeywords) { - (srv.options.ecmaVersion >= 6 ? jsKeywordsES6 : jsKeywords).forEach(function(kw) { - gather(kw, null, 0, function(rec) { rec.isKeyword = true; }); - }); - } - hookname = "variableCompletion"; - } - srv.signal(hookname, file, wordStart, wordEnd, gather); - - if (query.sort !== false) completions.sort(compareCompletions); - srv.cx.completingProperty = null; - - return {start: outputPos(query, file, wordStart), - end: outputPos(query, file, wordEnd), - isProperty: !!prop, - isObjectKey: !!isKey, - completions: completions}; - } - - function findProperties(srv, query) { - var prefix = query.prefix, found = []; - for (var prop in srv.cx.props) - if (prop != "" && (!prefix || prop.indexOf(prefix) === 0)) found.push(prop); - if (query.sort !== false) found.sort(compareCompletions); - return {completions: found}; - } - - function inBody(node, pos) { - var body = node.body, start, end; - if (!body) return false; - if (Array.isArray(body)) { - start = body[0].start; - end = body[body.length - 1].end; - } else { - start = body.start; - end = body.end; - } - return start <= pos && end >= pos; - } - - var findExpr = exports.findQueryExpr = function(file, query, wide) { - if (query.end == null) throw ternError("missing .query.end field"); - - if (query.variable) { - var scope = infer.scopeAt(file.ast, resolvePos(file, query.end), file.scope); - return {node: {type: "Identifier", name: query.variable, start: query.end, end: query.end + 1}, - state: scope}; - } else { - var start = query.start && resolvePos(file, query.start), end = resolvePos(file, query.end); - var expr = infer.findExpressionAt(file.ast, start, end, file.scope); - if (!expr) { - var span = infer.findClosestExpression(file.ast, start, end, file.scope); - if (span && !inBody(span.node, end) && - (wide || (start == null ? end : start) - span.node.start < 20 || span.node.end - end < 20)) - expr = span; - } - if (!expr) { - var around = infer.findExpressionAround(file.ast, start, end, file.scope); - if (around && !inBody(around.node, end) && - (around.node.type == "ObjectExpression" || wide || - (start == null ? end : start) - around.node.start < 20 || around.node.end - end < 20)) - expr = around; - } - return expr; - } - }; - - function findExprAround(file, query, wide) { - var start = query.start && resolvePos(file, query.start), end = resolvePos(file, query.end); - var expr = null; - var around = infer.findExpressionAround(file.ast, start, end, file.scope); - if (around && !inBody(around.node, end) && - (around.node.type == "ObjectExpression" || wide || - (start == null ? end : start) - around.node.start < 20 || around.node.end - end < 20)) - expr = around; - return expr; - } - - function findExprOrThrow(file, query, wide) { - var expr = findExpr(file, query, wide); - if (expr) return expr; - throw ternError("No expression at the given position."); - } - - function ensureObj(tp) { - if (!tp || !(tp = tp.getType()) || !(tp instanceof infer.Obj)) return null; - return tp; - } - - function findExprType(srv, query, file, expr) { - var type; - if (expr) { - infer.resetGuessing(); - type = infer.expressionType(expr); - } - var typeHandlers = srv.hasHandler("typeAt"); - if (typeHandlers) { - var pos = resolvePos(file, query.end); - for (var i = 0; i < typeHandlers.length; i++) - type = typeHandlers[i](file, pos, expr, type); - } - if (!type) throw ternError("No type found at the given position."); - - var objProp; - if (expr.node.type == "ObjectExpression" && query.end != null && - (objProp = pointInProp(expr.node, resolvePos(file, query.end)))) { - var name = objProp.key.name; - var fromCx = ensureObj(infer.typeFromContext(file.ast, expr)); - if (fromCx && fromCx.hasProp(name)) { - type = fromCx.hasProp(name); - } else { - var fromLocal = ensureObj(type); - if (fromLocal && fromLocal.hasProp(name)) - type = fromLocal.hasProp(name); - } - } - return type; - } - - function findTypeAtExpr(srv, query, file, expr) { - var exprName, exprType; - var type = findExprType(srv, query, file, expr), exprType = type; - if (query.preferFunction) - type = type.getFunctionType() || type.getType(); - else - type = type.getType(); - - if (expr) { - if (expr.node.type == "Identifier") - exprName = expr.node.name; - else if (expr.node.type == "MemberExpression" && !expr.node.computed) - exprName = expr.node.property.name; - else if (expr.node.type == "MethodDefinition" && !expr.node.computed) - exprName = expr.node.key.name; - } - - if (query.depth != null && typeof query.depth != "number") - throw ternError(".query.depth must be a number"); - - return [type, exprName, exprType]; - } - - function findTypeAt(srv, query, file) { - var type, exprName, exprType; - var expr = findExpr(file, query); - var typeResult = findTypeAtExpr(srv, query, file, expr); - type = typeResult[0]; - if (!type) { - expr = findExprAround(file, query); - typeResult = findTypeAtExpr(srv, query, file, expr); - type = typeResult[0]; - } - exprName = typeResult[1]; - exprType = typeResult[2]; - - var result = {guess: infer.didGuess(), - type: infer.toString(exprType, query.depth), - name: type && type.name, - exprName: exprName, - doc: exprType.doc, - url: exprType.url}; - if (type) storeTypeDocs(query, type, result); - - return clean(result); - } - - function parseDoc(query, doc) { - if (!doc) return null; - if (query.docFormat == "full") return doc; - var parabreak = /.\n[\s@\n]/.exec(doc); - if (parabreak) doc = doc.slice(0, parabreak.index + 1); - doc = doc.replace(/\n\s*/g, " "); - if (doc.length < 100) return doc; - var sentenceEnd = /[\.!?] [A-Z]/g; - sentenceEnd.lastIndex = 80; - var found = sentenceEnd.exec(doc); - if (found) doc = doc.slice(0, found.index + 1); - return doc; - } - - function findDocs(srv, query, file) { - var expr = findExpr(file, query); - var type = findExprType(srv, query, file, expr); - var inner = type.getType(); - if (!inner) { - expr = findExprAround(file, query); - type = findExprType(srv, query, file, expr); - inner = type.getType(); - } - var result = {url: type.url, doc: parseDoc(query, type.doc), type: infer.toString(type)}; - if (inner) storeTypeDocs(query, inner, result); - return clean(result); - } - - function storeTypeDocs(query, type, out) { - if (!out.url) out.url = type.url; - if (!out.doc) out.doc = parseDoc(query, type.doc); - if (!out.origin) out.origin = type.origin; - var ctor, boring = infer.cx().protos; - if (!out.url && !out.doc && type.proto && (ctor = type.proto.hasCtor) && - type.proto != boring.Object && type.proto != boring.Function && type.proto != boring.Array) { - out.url = ctor.url; - out.doc = parseDoc(query, ctor.doc); - } - } - - var getSpan = exports.getSpan = function(obj) { - if (!obj.origin) return; - if (obj.originNode) { - var node = obj.originNode; - if (/^Function/.test(node.type) && node.id) node = node.id; - return {origin: obj.origin, node: node}; - } - if (obj.span) return {origin: obj.origin, span: obj.span}; - }; - - var storeSpan = exports.storeSpan = function(srv, query, span, target) { - target.origin = span.origin; - if (span.span) { - var m = /^(\d+)\[(\d+):(\d+)\]-(\d+)\[(\d+):(\d+)\]$/.exec(span.span); - target.start = query.lineCharPositions ? {line: Number(m[2]), ch: Number(m[3])} : Number(m[1]); - target.end = query.lineCharPositions ? {line: Number(m[5]), ch: Number(m[6])} : Number(m[4]); - } else { - var file = srv.fileMap[span.origin]; - target.start = outputPos(query, file, span.node.start); - target.end = outputPos(query, file, span.node.end); - } - }; - - function findDef(srv, query, file) { - var expr = findExpr(file, query); - var type = findExprType(srv, query, file, expr); - if (infer.didGuess()) return {}; - - var span = getSpan(type); - var result = {url: type.url, doc: parseDoc(query, type.doc), origin: type.origin}; - - if (type.types) for (var i = type.types.length - 1; i >= 0; --i) { - var tp = type.types[i]; - storeTypeDocs(query, tp, result); - if (!span) span = getSpan(tp); - } - - if (span && span.node) { // refers to a loaded file - var spanFile = span.node.sourceFile || srv.fileMap[span.origin]; - var start = outputPos(query, spanFile, span.node.start), end = outputPos(query, spanFile, span.node.end); - result.start = start; result.end = end; - result.file = span.origin; - var cxStart = Math.max(0, span.node.start - 50); - result.contextOffset = span.node.start - cxStart; - result.context = spanFile.text.slice(cxStart, cxStart + 50); - } else if (span) { // external - result.file = span.origin; - storeSpan(srv, query, span, result); - } - return clean(result); - } - - function findRefsToVariable(srv, query, file, expr, isRename) { - var name = expr.node.name; - - for (var scope = expr.state; scope && !(name in scope.props); scope = scope.prev) {} - if (!scope) throw ternError("Could not find a definition for " + name); - - var type, refs = []; - function storeRef(file) { - return function(node, scopeHere, ancestors) { - var value = {file: file.name, - start: outputPos(query, file, node.start), - end: outputPos(query, file, node.end)}; - if (isRename) { - for (var s = scopeHere; s != scope; s = s.prev) { - var exists = s.hasProp(isRename); - if (exists) - throw ternError("Renaming `" + name + "` to `" + isRename + "` would make a variable at line " + - (asLineChar(file, node.start).line + 1) + " point to the definition at line " + - (asLineChar(file, exists.name.start).line + 1)); - } - var parent = ancestors[ancestors.length - 2]; - if (parent && parent.type == "Property" && parent.key == parent.value) - value.isShorthand = true; - } - refs.push(value); - }; - } - - if (scope.originNode) { - type = "local"; - if (isRename) { - for (var prev = scope.prev; prev; prev = prev.prev) - if (isRename in prev.props) break; - if (prev) infer.findRefs(scope.originNode, scope, isRename, prev, function(node) { - throw ternError("Renaming `" + name + "` to `" + isRename + "` would shadow the definition used at line " + - (asLineChar(file, node.start).line + 1)); - }); - } - infer.findRefs(scope.originNode, scope, name, scope, storeRef(file)); - } else { - type = "global"; - if (query.onlySourceFile) { - infer.findRefs(file.ast, file.scope, name, scope, storeRef(file)); - } else { - for (var i = 0; i < srv.files.length; ++i) { - var cur = srv.files[i]; - infer.findRefs(cur.ast, cur.scope, name, scope, storeRef(cur)); - } - } - } - - return {refs: refs, type: type, name: name}; - } - - function findRefsToProperty(srv, query, sourceFile, expr, prop) { - var exprType = infer.expressionType(expr); - if (expr.node.type == "MethodDefinition") { - exprType = exprType.propertyOf; - } - var objType = exprType.getObjType(); - if (!objType) throw ternError("Couldn't determine type of base object."); - - var refs = []; - function storeRef(file) { - return function(node) { - refs.push({file: file.name, - start: outputPos(query, file, node.start), - end: outputPos(query, file, node.end)}); - }; - } - - if (query.onlySourceFile) { - infer.findPropRefs(sourceFile.ast, sourceFile.scope, objType, prop.name, storeRef(sourceFile)); - } else { - for (var i = 0; i < srv.files.length; ++i) { - var cur = srv.files[i]; - infer.findPropRefs(cur.ast, cur.scope, objType, prop.name, storeRef(cur)); - } - } - - return {refs: refs, name: prop.name}; - } - - function findRefs(srv, query, file) { - var expr = findExprOrThrow(file, query, true); - if (expr && expr.node.type == "Identifier") { - return findRefsToVariable(srv, query, file, expr); - } else if (expr && expr.node.type == "MemberExpression" && !expr.node.computed) { - var p = expr.node.property; - expr.node = expr.node.object; - return findRefsToProperty(srv, query, file, expr, p); - } else if (expr && expr.node.type == "ObjectExpression") { - var pos = resolvePos(file, query.end); - for (var i = 0; i < expr.node.properties.length; ++i) { - var k = expr.node.properties[i].key; - if (k.start <= pos && k.end >= pos) - return findRefsToProperty(srv, query, file, expr, k); - } - } else if (expr && expr.node.type == "MethodDefinition") { - var p = expr.node.key; - return findRefsToProperty(srv, query, file, expr, p); - } - throw ternError("Not at a variable or property name."); - } - - function buildRename(srv, query, file) { - if (typeof query.newName != "string") throw ternError(".query.newName should be a string"); - var expr = findExprOrThrow(file, query); - if (!expr || expr.node.type != "Identifier") throw ternError("Not at a variable."); - - var data = findRefsToVariable(srv, query, file, expr, query.newName), refs = data.refs; - delete data.refs; - data.files = srv.files.map(function(f){return f.name;}); - - var changes = data.changes = []; - for (var i = 0; i < refs.length; ++i) { - var use = refs[i]; - if (use.isShorthand) use.text = expr.node.name + ": " + query.newName; - else use.text = query.newName; - changes.push(use); - } - - return data; - } - - function listFiles(srv) { - return {files: srv.files.map(function(f){return f.name;})}; - } - - exports.version = "0.24.1"; -}); -// Type description parser -// -// Type description JSON files (such as ecmascript.json and browser.json) -// are used to -// -// A) describe types that come from native code -// -// B) to cheaply load the types for big libraries, or libraries that -// can't be inferred well - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - return exports.init = mod; - if (typeof define == "function" && define.amd) // AMD - return define({init: mod}); - tern.def = {init: mod}; -})(function(exports, infer) { - "use strict"; - - function hop(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); - } - - var TypeParser = exports.TypeParser = function(spec, start, base, forceNew) { - this.pos = start || 0; - this.spec = spec; - this.base = base; - this.forceNew = forceNew; - }; - - function unwrapType(type, self, args) { - return type.call ? type(self, args) : type; - } - - function extractProp(type, prop) { - if (prop == "!ret") { - if (type.retval) return type.retval; - var rv = new infer.AVal; - type.propagate(new infer.IsCallee(infer.ANull, [], null, rv)); - return rv; - } else { - return type.getProp(prop); - } - } - - function computedFunc(name, args, retType, generator) { - return function(self, cArgs) { - var realArgs = []; - for (var i = 0; i < args.length; i++) realArgs.push(unwrapType(args[i], self, cArgs)); - return new infer.Fn(name, infer.ANull, realArgs, unwrapType(retType, self, cArgs), generator); - }; - } - function computedUnion(types) { - return function(self, args) { - var union = new infer.AVal; - for (var i = 0; i < types.length; i++) unwrapType(types[i], self, args).propagate(union); - union.maxWeight = 1e5; - return union; - }; - } - function computedArray(inner) { - return function(self, args) { - return new infer.Arr(inner(self, args)); - }; - } - function computedTuple(types) { - return function(self, args) { - return new infer.Arr(types.map(function(tp) { return unwrapType(tp, self, args) })); - }; - } - function computedObject(names, types) { - return function(self, args) { - var obj = new infer.Obj; - names.forEach(function (prop, i) { - obj.defProp(prop).addType(unwrapType(types[i], self, args)); - }); - return obj; - }; - } - - TypeParser.prototype = { - eat: function(str) { - if (str.length == 1 ? this.spec.charAt(this.pos) == str : this.spec.indexOf(str, this.pos) == this.pos) { - this.pos += str.length; - return true; - } - }, - word: function(re) { - var word = "", ch, re = re || /[\w$]/; - while ((ch = this.spec.charAt(this.pos)) && re.test(ch)) { word += ch; ++this.pos; } - return word; - }, - error: function() { - throw new Error("Unrecognized type spec: " + this.spec + " (at " + this.pos + ")"); - }, - parseFnType: function(comp, name, top, generator) { - var args = [], names = [], computed = false; - if (!this.eat(")")) for (var i = 0; ; ++i) { - var colon = this.spec.indexOf(": ", this.pos), argname; - if (colon != -1) { - argname = this.spec.slice(this.pos, colon); - if (/^(\.\.\.)?[$\w?]+$/.test(argname)) - this.pos = colon + 2; - else - argname = null; - } - names.push(argname); - var argType = this.parseType(comp); - if (argType.call) computed = true; - args.push(argType); - if (!this.eat(", ")) { - this.eat(")") || this.error(); - break; - } - } - var retType, computeRet, computeRetStart, fn; - if (this.eat(" -> ")) { - var retStart = this.pos; - retType = this.parseType(true); - if (retType.call && !computed) { - computeRet = retType; - retType = infer.ANull; - computeRetStart = retStart; - } - } else { - retType = infer.ANull; - } - if (computed) return computedFunc(name, args, retType, generator); - - if (top && (fn = this.base)) - infer.Fn.call(this.base, name, infer.ANull, args, names, retType, generator); - else - fn = new infer.Fn(name, infer.ANull, args, names, retType, generator); - if (computeRet) fn.computeRet = computeRet; - if (computeRetStart != null) fn.computeRetSource = this.spec.slice(computeRetStart, this.pos); - return fn; - }, - parseType: function(comp, name, top) { - var main = this.parseTypeMaybeProp(comp, name, top); - if (!this.eat("|")) return main; - var types = [main], computed = main.call; - for (;;) { - var next = this.parseTypeMaybeProp(comp, name, top); - types.push(next); - if (next.call) computed = true; - if (!this.eat("|")) break; - } - if (computed) return computedUnion(types); - var union = new infer.AVal; - for (var i = 0; i < types.length; i++) types[i].propagate(union); - union.maxWeight = 1e5; - return union; - }, - parseTypeMaybeProp: function(comp, name, top) { - var result = this.parseTypeInner(comp, name, top); - while (comp && this.eat(".")) result = this.extendWithProp(result); - return result; - }, - extendWithProp: function(base) { - var propName = this.word(/[\w<>$!:]/) || this.error(); - if (base.apply) return function(self, args) { - return extractProp(base(self, args), propName); - }; - return extractProp(base, propName); - }, - parseTypeInner: function(comp, name, top) { - var gen; - if (this.eat("fn(") || (gen = this.eat("fn*("))) { - return this.parseFnType(comp, name, top, gen); - } else if (this.eat("[")) { - var inner = this.parseType(comp), types, computed = inner.call; - while (this.eat(", ")) { - if (!types) types = [inner]; - var next = this.parseType(comp); - types.push(next); - computed = computed || next.call; - } - this.eat("]") || this.error(); - if (computed) return types ? computedTuple(types) : computedArray(inner); - if (top && this.base) { - infer.Arr.call(this.base, types || inner); - return this.base; - } - return new infer.Arr(types || inner); - } else if (this.eat("{")) { - var types = [], names = [], computed = false; - if (!this.eat("}")) { - for (var i = 0; ; ++i) { - var colon = this.spec.indexOf(": ", this.pos), propName; - if (colon != -1) { - propName = this.spec.slice(this.pos, colon); - if (/^[$\w?]+$/.test(propName)) - this.pos = colon + 2; - else - propName = null; - } - var propType = this.parseType(comp); - if (propType.call) computed = true; - names.push(propName); - types.push(propType); - if (!this.eat(", ")) { - this.eat("}") || this.error(); - break; - } - } - } - if (computed) return computedObject(names, types); - var obj = new infer.Obj; - names.forEach(function (prop, i) { - obj.defProp(prop).addType(types[i]); - }); - return obj; - } else if (this.eat("+")) { - var path = this.word(/[\w$<>\.:!]/); - var base = infer.cx().localDefs[path + ".prototype"]; - if (!base) { - var base = parsePath(path); - if (!(base instanceof infer.Obj)) return base; - var proto = descendProps(base, ["prototype"]); - if (proto && (proto = proto.getObjType())) - base = proto; - } - if (comp && this.eat("[")) return this.parsePoly(base); - if (top && this.base) { - this.base.proto = base; - var name = base.hasCtor && base.hasCtor.name || base.name; - if (name) this.base.name = name; - return this.base; - } - if (top && this.forceNew) return new infer.Obj(base); - return infer.getInstance(base); - } else if (this.eat(":")) { - var name = this.word(/[\w$\.]/); - return infer.getSymbol(name); - } else if (comp && this.eat("!")) { - var arg = this.word(/\d/); - if (arg) { - arg = Number(arg); - return function(_self, args) {return args[arg] || infer.ANull;}; - } else if (this.eat("this")) { - return function(self) {return self;}; - } else if (this.eat("custom:")) { - var fname = this.word(/[\w$]/); - return customFunctions[fname] || function() { return infer.ANull; }; - } else { - return this.fromWord("!" + this.word(/[\w$<>\.!:]/)); - } - } else if (this.eat("?")) { - return infer.ANull; - } else { - return this.fromWord(this.word(/[\w$<>\.!:`]/)); - } - }, - fromWord: function(spec) { - var cx = infer.cx(); - switch (spec) { - case "number": return cx.num; - case "string": return cx.str; - case "bool": return cx.bool; - case "": return cx.topScope; - } - if (cx.localDefs && spec in cx.localDefs) return cx.localDefs[spec]; - return parsePath(spec); - }, - parsePoly: function(base) { - var propName = "", match; - if (match = this.spec.slice(this.pos).match(/^\s*([\w$:]+)\s*=\s*/)) { - propName = match[1]; - this.pos += match[0].length; - } - var value = this.parseType(true); - if (!this.eat("]")) this.error(); - if (value.call) return function(self, args) { - var instance = new infer.Obj(base); - value(self, args).propagate(instance.defProp(propName)); - return instance; - }; - var instance = new infer.Obj(base); - value.propagate(instance.defProp(propName)); - return instance; - } - }; - - function addArgCallEffects(type) { - if (type instanceof infer.Fn && type.args) for (var i = 0; i < type.args.length; ++i) { - var arg = type.args[i]; - if (arg instanceof infer.Fn && arg.args && arg.args.length) addArgCallEffect(type, i); - } - } - - function addArgCallEffect(type, argNum) { - addEffect(type, function(_self, args) { - if (args[argNum]) args[argNum].propagate( - new infer.IsCallee(infer.cx().topScope, type.args[argNum].args, null, infer.ANull)); - }); - } - - function parseType(spec, name, base, forceNew) { - var type = new TypeParser(spec, null, base, forceNew).parseType(false, name, true); - if (type instanceof infer.AVal) type.types.forEach(addArgCallEffects); - else addArgCallEffects(type); - return type; - } - - function addEffect(fn, handler, replaceRet) { - var oldCmp = fn.computeRet, rv = fn.retval; - fn.computeRet = function(self, args, argNodes) { - var handled = handler(self, args, argNodes); - var old = oldCmp ? oldCmp(self, args, argNodes) : rv; - return replaceRet ? handled : old; - }; - } - - var parseEffect = exports.parseEffect = function(effect, fn) { - var m; - if (effect.indexOf("propagate ") == 0) { - var p = new TypeParser(effect, 10); - var origin = p.parseType(true); - if (!p.eat(" ")) p.error(); - var target = p.parseType(true); - addEffect(fn, function(self, args) { - unwrapType(origin, self, args).propagate(unwrapType(target, self, args)); - }); - } else if (effect.indexOf("call ") == 0) { - var andRet = effect.indexOf("and return ", 5) == 5; - var p = new TypeParser(effect, andRet ? 16 : 5); - var getCallee = p.parseType(true), getSelf = null, getArgs = []; - if (p.eat(" this=")) getSelf = p.parseType(true); - while (p.eat(" ")) getArgs.push(p.parseType(true)); - addEffect(fn, function(self, args) { - var callee = unwrapType(getCallee, self, args); - var slf = getSelf ? unwrapType(getSelf, self, args) : infer.ANull, as = []; - for (var i = 0; i < getArgs.length; ++i) as.push(unwrapType(getArgs[i], self, args)); - var result = andRet ? new infer.AVal : infer.ANull; - callee.propagate(new infer.IsCallee(slf, as, null, result)); - return result; - }, andRet); - } else if (m = effect.match(/^custom (\S+)\s*(.*)/)) { - var customFunc = customFunctions[m[1]]; - if (customFunc) addEffect(fn, m[2] ? customFunc(m[2]) : customFunc); - } else if (effect.indexOf("copy ") == 0) { - var p = new TypeParser(effect, 5); - var getFrom = p.parseType(true); - p.eat(" "); - var getTo = p.parseType(true); - addEffect(fn, function(self, args) { - var from = unwrapType(getFrom, self, args), to = unwrapType(getTo, self, args); - from.forAllProps(function(prop, val, local) { - if (local && prop != "") - to.propagate(new infer.DefProp(prop, val)); - }); - }); - } else { - throw new Error("Unknown effect type: " + effect); - } - }; - - var currentTopScope; - - var parsePath = exports.parsePath = function(path, scope) { - var cx = infer.cx(), cached = cx.paths[path], origPath = path; - if (cached != null) return cached; - cx.paths[path] = infer.ANull; - - var base = scope || currentTopScope || cx.topScope; - - if (cx.localDefs) for (var name in cx.localDefs) { - if (path.indexOf(name) == 0) { - if (path == name) return cx.paths[path] = cx.localDefs[path]; - if (path.charAt(name.length) == ".") { - base = cx.localDefs[name]; - path = path.slice(name.length + 1); - break; - } - } - } - - var result = descendProps(base, path.split(".")); - // Uncomment this to get feedback on your poorly written .json files - // if (result == infer.ANull) console.error("bad path: " + origPath + " (" + cx.curOrigin + ")") - cx.paths[origPath] = result == infer.ANull ? null : result; - return result; - }; - - function descendProps(base, parts) { - for (var i = 0; i < parts.length && base != infer.ANull; ++i) { - var prop = parts[i]; - if (prop.charAt(0) == "!") { - if (prop == "!proto") { - base = (base instanceof infer.Obj && base.proto) || infer.ANull; - } else { - var fn = base.getFunctionType(); - if (!fn) { - base = infer.ANull; - } else if (prop == "!ret") { - base = fn.retval && fn.retval.getType(false) || infer.ANull; - } else { - var arg = fn.args && fn.args[Number(prop.slice(1))]; - base = (arg && arg.getType(false)) || infer.ANull; - } - } - } else if (base instanceof infer.Obj && - (prop == "prototype" && base instanceof infer.Fn || base.hasProp(prop))) { - var propVal = base.getProp(prop); - if (!propVal || propVal.isEmpty()) - base = infer.ANull; - else - base = propVal.types[0]; - } else { - base = infer.ANull; - } - } - return base; - } - - function emptyObj(ctor) { - var empty = Object.create(ctor.prototype); - empty.props = Object.create(null); - empty.isShell = true; - return empty; - } - - function isSimpleAnnotation(spec) { - if (!spec["!type"] || /^(fn\(|\[|\+)/.test(spec["!type"])) return false; - for (var prop in spec) - if (prop != "!type" && prop != "!doc" && prop != "!url" && prop != "!span" && prop != "!data") - return false; - return true; - } - - function passOne(base, spec, path) { - if (!base) { - var tp = spec["!type"]; - if (tp) { - if (/^fn\(/.test(tp)) base = emptyObj(infer.Fn); - else if (tp.charAt(0) == "[") base = emptyObj(infer.Arr); - else if (tp.charAt(0) == "+") base = emptyObj(infer.Obj); - else throw new Error("Invalid !type spec: " + tp); - } else if (spec["!stdProto"]) { - base = infer.cx().protos[spec["!stdProto"]]; - } else { - base = emptyObj(infer.Obj); - } - base.name = path; - } - - for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) { - var inner = spec[name]; - if (typeof inner == "string" || isSimpleAnnotation(inner)) continue; - var prop = base.defProp(name); - passOne(prop.getObjType(), inner, path ? path + "." + name : name).propagate(prop); - } - return base; - } - - function passTwo(base, spec, path) { - if (base.isShell) { - delete base.isShell; - var tp = spec["!type"]; - if (tp) { - parseType(tp, path, base); - } else { - var proto = spec["!proto"] && parseType(spec["!proto"]); - infer.Obj.call(base, proto instanceof infer.Obj ? proto : true, path); - } - } - - var effects = spec["!effects"]; - if (effects && base instanceof infer.Fn) for (var i = 0; i < effects.length; ++i) - parseEffect(effects[i], base); - copyInfo(spec, base); - - for (var name in spec) if (hop(spec, name) && name.charCodeAt(0) != 33) { - var inner = spec[name], known = base.defProp(name), innerPath = path ? path + "." + name : name; - if (typeof inner == "string") { - if (known.isEmpty()) parseType(inner, innerPath).propagate(known); - } else { - if (!isSimpleAnnotation(inner)) - passTwo(known.getObjType(), inner, innerPath); - else if (known.isEmpty()) - parseType(inner["!type"], innerPath, null, true).propagate(known); - else - continue; - if (inner["!doc"]) known.doc = inner["!doc"]; - if (inner["!url"]) known.url = inner["!url"]; - if (inner["!span"]) known.span = inner["!span"]; - } - } - return base; - } - - function copyInfo(spec, type) { - if (spec["!doc"]) type.doc = spec["!doc"]; - if (spec["!url"]) type.url = spec["!url"]; - if (spec["!span"]) type.span = spec["!span"]; - if (spec["!data"]) type.metaData = spec["!data"]; - } - - function doLoadEnvironment(data, scope) { - var cx = infer.cx(), server = cx.parent; - - infer.addOrigin(cx.curOrigin = data["!name"] || "env#" + cx.origins.length); - cx.localDefs = cx.definitions[cx.curOrigin] = Object.create(null); - - if (server) server.signal("preLoadDef", data); - - passOne(scope, data); - - var def = data["!define"]; - if (def) { - for (var name in def) { - var spec = def[name]; - cx.localDefs[name] = typeof spec == "string" ? parsePath(spec) : passOne(null, spec, name); - } - for (var name in def) { - var spec = def[name]; - if (typeof spec != "string") passTwo(cx.localDefs[name], def[name], name); - } - } - - passTwo(scope, data); - - if (server) server.signal("postLoadDef", data); - - cx.curOrigin = cx.localDefs = null; - } - - exports.load = function(data, scope) { - if (!scope) scope = infer.cx().topScope; - var oldScope = currentTopScope; - currentTopScope = scope; - try { - doLoadEnvironment(data, scope); - } finally { - currentTopScope = oldScope; - } - }; - - exports.parse = function(data, origin, path) { - var cx = infer.cx(); - if (origin) { - cx.origin = origin; - cx.localDefs = cx.definitions[origin]; - } - - try { - if (typeof data == "string") - return parseType(data, path); - else - return passTwo(passOne(null, data, path), data, path); - } finally { - if (origin) cx.origin = cx.localDefs = null; - } - }; - - // Used to register custom logic for more involved effect or type - // computation. - var customFunctions = Object.create(null); - infer.registerFunction = function(name, f) { customFunctions[name] = f; }; - - var IsCreated = infer.constraint({ - construct: function(created, target, spec) { - this.created = created; - this.target = target; - this.spec = spec; - }, - addType: function(tp) { - if (tp instanceof infer.Obj && this.created++ < 5) { - var derived = new infer.Obj(tp), spec = this.spec; - if (spec instanceof infer.AVal) spec = spec.getObjType(false); - if (spec instanceof infer.Obj) for (var prop in spec.props) { - var cur = spec.props[prop].types[0]; - var p = derived.defProp(prop); - if (cur && cur instanceof infer.Obj && cur.props.value) { - var vtp = cur.props.value.getType(false); - if (vtp) p.addType(vtp); - } - } - this.target.addType(derived); - } - } - }); - - infer.registerFunction("Object_create", function(_self, args, argNodes) { - if (argNodes && argNodes.length && argNodes[0].type == "Literal" && argNodes[0].value == null) - return new infer.Obj(); - - var result = new infer.AVal; - if (args[0]) args[0].propagate(new IsCreated(0, result, args[1])); - return result; - }); - - var PropSpec = infer.constraint({ - construct: function(target) { this.target = target; }, - addType: function(tp) { - if (!(tp instanceof infer.Obj)) return; - if (tp.hasProp("value")) - tp.getProp("value").propagate(this.target); - else if (tp.hasProp("get")) - tp.getProp("get").propagate(new infer.IsCallee(infer.ANull, [], null, this.target)); - } - }); - - infer.registerFunction("Object_defineProperty", function(_self, args, argNodes) { - if (argNodes && argNodes.length >= 3 && argNodes[1].type == "Literal" && - typeof argNodes[1].value == "string") { - var obj = args[0], connect = new infer.AVal; - obj.propagate(new infer.DefProp(argNodes[1].value, connect, argNodes[1])); - args[2].propagate(new PropSpec(connect)); - } - return infer.ANull; - }); - - infer.registerFunction("Object_defineProperties", function(_self, args, argNodes) { - if (args.length >= 2) { - var obj = args[0]; - args[1].forAllProps(function(prop, val, local) { - if (!local) return; - var connect = new infer.AVal; - obj.propagate(new infer.DefProp(prop, connect, argNodes && argNodes[1])); - val.propagate(new PropSpec(connect)); - }); - } - return infer.ANull; - }); - - var IsBound = infer.constraint({ - construct: function(self, args, target) { - this.self = self; this.args = args; this.target = target; - }, - addType: function(tp) { - if (!(tp instanceof infer.Fn)) return; - this.target.addType(new infer.Fn(tp.name, infer.ANull, tp.args.slice(this.args.length), - tp.argNames.slice(this.args.length), tp.retval, tp.generator)); - this.self.propagate(tp.self); - for (var i = 0; i < Math.min(tp.args.length, this.args.length); ++i) - this.args[i].propagate(tp.args[i]); - } - }); - - infer.registerFunction("Function_bind", function(self, args) { - if (!args.length) return infer.ANull; - var result = new infer.AVal; - self.propagate(new IsBound(args[0], args.slice(1), result)); - return result; - }); - - infer.registerFunction("Array_ctor", function(_self, args) { - var arr = new infer.Arr; - if (args.length != 1 || !args[0].hasType(infer.cx().num)) { - var content = arr.getProp(""); - for (var i = 0; i < args.length; ++i) args[i].propagate(content); - } - return arr; - }); - - function makePromise() { - var defs = infer.cx().definitions.ecmascript; - return defs && new infer.Obj(defs["Promise.prototype"]); - } - - infer.registerFunction("Promise_ctor", function(_self, args, argNodes) { - var self = makePromise(); - if (!self || args.length < 1) return infer.ANull; - var valProp = self.defProp(":t", argNodes && argNodes[0]); - var valArg = new infer.AVal; - valArg.propagate(valProp); - var exec = new infer.Fn("execute", infer.ANull, [valArg], ["value"], infer.ANull); - var reject = infer.cx().definitions.ecmascript.Promise_reject; - args[0].propagate(new infer.IsCallee(infer.ANull, [exec, reject], null, infer.ANull)); - return self; - }); - - // Definition for Promise.resolve() - // The behavior is different for Promise and non-Promise arguments, so we - // need a custom definition to handle the different cases properly. - infer.registerFunction("Promise_resolve", function(_self, args, argNodes) { - var self = makePromise(); - if (!self) return infer.ANull; - if (args.length) { - var valProp = self.defProp(":t", argNodes && argNodes[0]); - var valArg = new infer.AVal; - valArg.propagate(valProp); - args[0].propagate(new PromiseResolvesTo(valArg)); - } - return self; - }); - - var PromiseResolvesTo = infer.constraint({ - construct: function(output) { this.output = output; }, - addType: function(tp) { - if (tp.constructor == infer.Obj && tp.name == "Promise" && tp.hasProp(":t")) - tp.getProp(":t").propagate(this.output); - else - tp.propagate(this.output); - } - }); - - var WG_PROMISE_KEEP_VALUE = 50; - - infer.registerFunction("Promise_then", function(self, args, argNodes) { - var fn = args.length && args[0].getFunctionType(); - var defs = infer.cx().definitions.ecmascript; - if (!fn || !defs) return self; - - var result = new infer.Obj(defs["Promise.prototype"]); - var value = result.defProp(":t", argNodes && argNodes[0]), ty; - if (fn.retval.isEmpty() && (ty = self.getType()) instanceof infer.Obj && ty.hasProp(":t")) - ty.getProp(":t").propagate(value, WG_PROMISE_KEEP_VALUE); - fn.retval.propagate(new PromiseResolvesTo(value)); - return result; - }); - - infer.registerFunction("getOwnPropertySymbols", function(_self, args) { - if (!args.length) return infer.ANull; - var result = new infer.AVal; - args[0].forAllProps(function(prop, _val, local) { - if (local && prop.charAt(0) == ":") result.addType(infer.getSymbol(prop.slice(1))); - }); - return result; - }); - - infer.registerFunction("getSymbol", function(_self, _args, argNodes) { - if (argNodes && argNodes.length && argNodes[0].type == "Literal" && typeof argNodes[0].value == "string") - return infer.getSymbol(argNodes[0].value); - else - return infer.ANull; - }); - - return exports; -}); -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - return mod(exports); - if (typeof define == "function" && define.amd) // AMD - return define(["exports"], mod); - mod(tern.comment || (tern.comment = {})); -})(function(exports) { - function isSpace(ch) { - return (ch < 14 && ch > 8) || ch === 32 || ch === 160; - } - - function onOwnLine(text, pos) { - for (; pos > 0; --pos) { - var ch = text.charCodeAt(pos - 1); - if (ch == 10) break; - if (!isSpace(ch)) return false; - } - return true; - } - - // Gather comments directly before a function - exports.commentsBefore = function(text, pos) { - var found = null, emptyLines = 0, topIsLineComment; - out: while (pos > 0) { - var prev = text.charCodeAt(pos - 1); - if (prev == 10) { - for (var scan = --pos, sawNonWS = false; scan > 0; --scan) { - prev = text.charCodeAt(scan - 1); - if (prev == 47 && text.charCodeAt(scan - 2) == 47) { - if (!onOwnLine(text, scan - 2)) break out; - var content = text.slice(scan, pos); - if (!emptyLines && topIsLineComment) found[0] = content + "\n" + found[0]; - else (found || (found = [])).unshift(content); - topIsLineComment = true; - emptyLines = 0; - pos = scan - 2; - break; - } else if (prev == 10) { - if (!sawNonWS && ++emptyLines > 1) break out; - break; - } else if (!sawNonWS && !isSpace(prev)) { - sawNonWS = true; - } - } - } else if (prev == 47 && text.charCodeAt(pos - 2) == 42) { - for (var scan = pos - 2; scan > 1; --scan) { - if (text.charCodeAt(scan - 1) == 42 && text.charCodeAt(scan - 2) == 47) { - if (!onOwnLine(text, scan - 2)) break out; - (found || (found = [])).unshift(text.slice(scan, pos - 2)); - topIsLineComment = false; - emptyLines = 0; - break; - } - } - pos = scan - 2; - } else if (isSpace(prev)) { - --pos; - } else { - break; - } - } - return found; - }; - - exports.commentAfter = function(text, pos) { - while (pos < text.length) { - var next = text.charCodeAt(pos); - if (next == 47) { - var after = text.charCodeAt(pos + 1), end; - if (after == 47) // line comment - end = text.indexOf("\n", pos + 2); - else if (after == 42) // block comment - end = text.indexOf("*/", pos + 2); - else - return; - return text.slice(pos + 2, end < 0 ? text.length : end); - } else if (isSpace(next)) { - ++pos; - } - } - }; - - exports.ensureCommentsBefore = function(text, node) { - if (node.hasOwnProperty("commentsBefore")) return node.commentsBefore; - return node.commentsBefore = exports.commentsBefore(text, node.start); - }; -}); -// Main type inference engine - -// Walks an AST, building up a graph of abstract values and constraints -// that cause types to flow from one node to another. Also defines a -// number of utilities for accessing ASTs and scopes. - -// Analysis is done in a context, which is tracked by the dynamically -// bound cx variable. Use withContext to set the current context. - -// For memory-saving reasons, individual types export an interface -// similar to abstract values (which can hold multiple types), and can -// thus be used in place abstract values that only ever contain a -// single type. - -(function(root, mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - return mod(exports, require("acorn"), require("acorn-loose"), require("acorn-walk"), - require("./def"), require("./signal")); - if (typeof define == "function" && define.amd) // AMD - return define(["exports", "acorn/dist/acorn", "acorn-loose/dist/acorn-loose", "acorn-walk/dist/walk", "./def", "./signal"], mod); - mod(root.tern || (root.tern = {}), acorn, acorn.loose, acorn.walk, tern.def, tern.signal); // Plain browser env -})(this, function(exports, acorn, acorn_loose, walk, def, signal) { - "use strict"; - - var toString = exports.toString = function(type, maxDepth, parent) { - if (!type || type == parent || maxDepth && maxDepth < -3) return "?"; - return type.toString(maxDepth, parent); - }; - - // A variant of AVal used for unknown, dead-end values. Also serves - // as prototype for AVals, Types, and Constraints because it - // implements 'empty' versions of all the methods that the code - // expects. - var ANull = exports.ANull = signal.mixin({ - addType: function() {}, - propagate: function() {}, - getProp: function() { return ANull; }, - forAllProps: function() {}, - hasType: function() { return false; }, - isEmpty: function() { return true; }, - getFunctionType: function() {}, - getObjType: function() {}, - getSymbolType: function() {}, - getType: function() {}, - gatherProperties: function() {}, - propagatesTo: function() {}, - typeHint: function() {}, - propHint: function() {}, - toString: function() { return "?"; } - }); - - function extend(proto, props) { - var obj = Object.create(proto); - if (props) for (var prop in props) obj[prop] = props[prop]; - return obj; - } - - // ABSTRACT VALUES - - var WG_DEFAULT = 100, WG_NEW_INSTANCE = 90, WG_MADEUP_PROTO = 10, - WG_MULTI_MEMBER = 6, WG_CATCH_ERROR = 6, - WG_PHANTOM_OBJ = 1, - WG_GLOBAL_THIS = 90, WG_SPECULATIVE_THIS = 2, WG_SPECULATIVE_PROTO_THIS = 4; - - var AVal = exports.AVal = function() { - this.types = []; - this.forward = null; - this.maxWeight = 0; - }; - AVal.prototype = extend(ANull, { - addType: function(type, weight) { - weight = weight || WG_DEFAULT; - if (this.maxWeight < weight) { - this.maxWeight = weight; - if (this.types.length == 1 && this.types[0] == type) return; - this.types.length = 0; - } else if (this.maxWeight > weight || this.types.indexOf(type) > -1) { - return; - } - - this.signal("addType", type); - this.types.push(type); - var forward = this.forward; - if (forward) withWorklist(function(add) { - for (var i = 0; i < forward.length; ++i) add(type, forward[i], weight); - }); - }, - - propagate: function(target, weight) { - if (target == ANull || (target instanceof Type && this.forward && this.forward.length > 2)) return; - if (weight && weight != WG_DEFAULT) target = new Muffle(target, weight); - (this.forward || (this.forward = [])).push(target); - var types = this.types; - if (types.length) withWorklist(function(add) { - for (var i = 0; i < types.length; ++i) add(types[i], target, weight); - }); - }, - - getProp: function(prop) { - if (ignoredProp(prop)) return ANull; - var found = (this.props || (this.props = Object.create(null)))[prop]; - if (!found) { - found = this.props[prop] = new AVal; - this.propagate(new GetProp(prop, found)); - } - return found; - }, - - forAllProps: function(c) { - this.propagate(new ForAllProps(c)); - }, - - hasType: function(type) { - return this.types.indexOf(type) > -1; - }, - isEmpty: function() { return this.types.length === 0; }, - getFunctionType: function() { - for (var i = this.types.length - 1; i >= 0; --i) - if (this.types[i] instanceof Fn) return this.types[i]; - }, - getObjType: function() { - var seen = null; - for (var i = this.types.length - 1; i >= 0; --i) { - var type = this.types[i]; - if (!(type instanceof Obj)) continue; - if (type.name) return type; - if (!seen) seen = type; - } - return seen; - }, - - getSymbolType: function() { - for (var i = this.types.length - 1; i >= 0; --i) - if (this.types[i] instanceof Sym) return this.types[i]; - }, - - getType: function(guess) { - if (this.types.length === 0 && guess !== false) return this.makeupType(); - if (this.types.length === 1) return this.types[0]; - return canonicalType(this.types); - }, - - toString: function(maxDepth, parent) { - if (this.types.length == 0) return toString(this.makeupType(), maxDepth, parent); - if (this.types.length == 1) return toString(this.types[0], maxDepth, parent); - var simplified = simplifyTypes(this.types); - if (simplified.length > 2) return "?"; - return simplified.map(function(tp) { return toString(tp, maxDepth, parent); }).join("|"); - }, - - makeupPropType: function(obj) { - var propName = this.propertyName; - - var protoProp = obj.proto && obj.proto.hasProp(propName); - if (protoProp) { - var fromProto = protoProp.getType(); - if (fromProto) return fromProto; - } - - if (propName != "") { - var computedProp = obj.hasProp(""); - if (computedProp) return computedProp.getType(); - } else if (obj.props[""] != this) { - for (var prop in obj.props) { - var val = obj.props[prop]; - if (!val.isEmpty()) return val.getType(); - } - } - }, - - makeupType: function() { - var computed = this.propertyOf && this.makeupPropType(this.propertyOf); - if (computed) return computed; - - if (!this.forward) return null; - for (var i = this.forward.length - 1; i >= 0; --i) { - var hint = this.forward[i].typeHint(); - if (hint && !hint.isEmpty()) {guessing = true; return hint;} - } - - var props = Object.create(null), foundProp = null; - for (var i = 0; i < this.forward.length; ++i) { - var prop = this.forward[i].propHint(); - if (prop && prop != "length" && prop != "" && prop != "✖" && prop != cx.completingProperty) { - props[prop] = true; - foundProp = prop; - } - } - if (!foundProp) return null; - - var objs = objsWithProp(foundProp); - if (objs) { - var matches = []; - search: for (var i = 0; i < objs.length; ++i) { - var obj = objs[i]; - for (var prop in props) if (!obj.hasProp(prop)) continue search; - if (obj.hasCtor) obj = getInstance(obj); - matches.push(obj); - } - var canon = canonicalType(matches); - if (canon) {guessing = true; return canon;} - } - }, - - typeHint: function() { return this.types.length ? this.getType() : null; }, - propagatesTo: function() { return this; }, - - gatherProperties: function(f, depth) { - for (var i = 0; i < this.types.length; ++i) - this.types[i].gatherProperties(f, depth); - }, - - guessProperties: function(f) { - if (this.forward) for (var i = 0; i < this.forward.length; ++i) { - var prop = this.forward[i].propHint(); - if (prop) f(prop, null, 0); - } - var guessed = this.makeupType(); - if (guessed) guessed.gatherProperties(f); - } - }); - - function similarAVal(a, b, depth) { - var typeA = a.getType(false), typeB = b.getType(false); - if (!typeA || !typeB) return true; - return similarType(typeA, typeB, depth); - } - - function similarType(a, b, depth) { - if (!a || depth >= 5) return b; - if (!a || a == b) return a; - if (!b) return a; - if (a.constructor != b.constructor) return false; - if (a.constructor == Arr) { - var innerA = a.getProp("").getType(false); - if (!innerA) return b; - var innerB = b.getProp("").getType(false); - if (!innerB || similarType(innerA, innerB, depth + 1)) return b; - } else if (a.constructor == Obj) { - var propsA = 0, propsB = 0, same = 0; - for (var prop in a.props) { - propsA++; - if (prop in b.props && similarAVal(a.props[prop], b.props[prop], depth + 1)) - same++; - } - for (var prop in b.props) propsB++; - if (propsA && propsB && same < Math.max(propsA, propsB) / 2) return false; - return propsA > propsB ? a : b; - } else if (a.constructor == Fn) { - if (a.args.length != b.args.length || - !a.args.every(function(tp, i) { return similarAVal(tp, b.args[i], depth + 1); }) || - !similarAVal(a.retval, b.retval, depth + 1) || !similarAVal(a.self, b.self, depth + 1)) - return false; - return a; - } else { - return false; - } - } - - var simplifyTypes = exports.simplifyTypes = function(types) { - var found = []; - outer: for (var i = 0; i < types.length; ++i) { - var tp = types[i]; - for (var j = 0; j < found.length; j++) { - var similar = similarType(tp, found[j], 0); - if (similar) { - found[j] = similar; - continue outer; - } - } - found.push(tp); - } - return found; - }; - - function canonicalType(types) { - var arrays = 0, fns = 0, objs = 0, prim = null; - for (var i = 0; i < types.length; ++i) { - var tp = types[i]; - if (tp instanceof Arr) ++arrays; - else if (tp instanceof Fn) ++fns; - else if (tp instanceof Obj) ++objs; - else if (tp instanceof Prim) { - if (prim && tp.name != prim.name) return null; - prim = tp; - } - } - var kinds = (arrays && 1) + (fns && 1) + (objs && 1) + (prim && 1); - if (kinds > 1) return null; - if (prim) return prim; - - var maxScore = 0, maxTp = null; - for (var i = 0; i < types.length; ++i) { - var tp = types[i], score = 0; - if (arrays) { - score = tp.getProp("").isEmpty() ? 1 : 2; - } else if (fns) { - score = 1; - for (var j = 0; j < tp.args.length; ++j) if (!tp.args[j].isEmpty()) ++score; - if (!tp.retval.isEmpty()) ++score; - } else if (objs) { - score = tp.name ? 100 : 2; - } - if (score >= maxScore) { maxScore = score; maxTp = tp; } - } - return maxTp; - } - - // PROPAGATION STRATEGIES - - var constraint = exports.constraint = function(methods) { - var ctor = function() { - this.origin = cx.curOrigin; - this.construct.apply(this, arguments); - }; - ctor.prototype = Object.create(ANull); - for (var m in methods) if (methods.hasOwnProperty(m)) ctor.prototype[m] = methods[m]; - return ctor; - }; - - var GetProp = constraint({ - construct: function(prop, target) { - this.prop = prop; this.target = target; - }, - addType: function(type, weight) { - if (type.getProp) - type.getProp(this.prop).propagate(this.target, weight); - }, - propHint: function() { return this.prop; }, - propagatesTo: function() { - if (this.prop == "" || !/[^\w_]/.test(this.prop)) - return {target: this.target, pathExt: "." + this.prop}; - } - }); - - var DefProp = exports.PropHasSubset = exports.DefProp = constraint({ - construct: function(prop, type, originNode) { - this.prop = prop; this.type = type; this.originNode = originNode; - }, - addType: function(type, weight) { - if (!(type instanceof Obj)) return; - var prop = type.defProp(this.prop, this.originNode); - if (!prop.origin) prop.origin = this.origin; - this.type.propagate(prop, weight); - }, - propHint: function() { return this.prop; } - }); - - var ForAllProps = constraint({ - construct: function(c) { this.c = c; }, - addType: function(type) { - if (!(type instanceof Obj)) return; - type.forAllProps(this.c); - } - }); - - function withDisabledComputing(fn, body) { - cx.disabledComputing = {fn: fn, prev: cx.disabledComputing}; - var result = body(); - cx.disabledComputing = cx.disabledComputing.prev; - return result; - } - var IsCallee = exports.IsCallee = constraint({ - construct: function(self, args, argNodes, retval) { - this.self = self; this.args = args; this.argNodes = argNodes; this.retval = retval; - this.disabled = cx.disabledComputing; - }, - addType: function(fn, weight) { - if (!(fn instanceof Fn)) return; - for (var i = 0; i < this.args.length; ++i) { - if (i < fn.args.length) this.args[i].propagate(fn.args[i], weight); - if (fn.arguments) this.args[i].propagate(fn.arguments, weight); - } - if (!fn.isArrowFn()) - this.self.propagate(fn.self, this.self == cx.topScope ? WG_GLOBAL_THIS : weight); - var compute = fn.computeRet, result = fn.retval; - if (compute) for (var d = this.disabled; d; d = d.prev) - if (d.fn == fn || fn.originNode && d.fn.originNode == fn.originNode) compute = null; - if (compute) { - var old = cx.disabledComputing; - cx.disabledComputing = this.disabled; - result = compute(this.self, this.args, this.argNodes); - cx.disabledComputing = old; - } - if (fn.async && !fn.generator) { - var tp = result.getType(); - if (!(tp && tp.constructor == Obj && tp.name == "Promise")) { - var defs = cx.definitions.ecmascript; - var rtnval = defs && new Obj(defs["Promise.prototype"]); - if (rtnval) { - rtnval.getType().propagate(new DefProp(':t', result)); - result = rtnval; - } - } - } - maybeIterator(fn, result).propagate(this.retval, weight); - }, - typeHint: function() { - var names = []; - for (var i = 0; i < this.args.length; ++i) names.push("?"); - return new Fn(null, this.self, this.args, names, ANull); - }, - propagatesTo: function() { - return {target: this.retval, pathExt: ".!ret"}; - } - }); - - var HasMethodCall = constraint({ - construct: function(propName, args, argNodes, retval) { - this.propName = propName; this.args = args; this.argNodes = argNodes; this.retval = retval; - this.disabled = cx.disabledComputing; - }, - addType: function(obj, weight) { - var callee = new IsCallee(obj, this.args, this.argNodes, this.retval); - callee.disabled = this.disabled; - obj.getProp(this.propName).propagate(callee, weight); - }, - propHint: function() { return this.propName; } - }); - - var IsCtor = exports.IsCtor = constraint({ - construct: function(target, noReuse) { - this.target = target; this.noReuse = noReuse; - }, - addType: function(f, weight) { - if (!(f instanceof Fn)) return; - if (cx.parent && !cx.parent.options.reuseInstances) this.noReuse = true; - f.getProp("prototype").propagate(new IsProto(this.noReuse ? false : f, this.target), weight); - } - }); - - var getInstance = exports.getInstance = function(obj, ctor) { - if (ctor === false || obj == null) return new Obj(obj); - - if (!ctor) ctor = obj.hasCtor; - if (!obj.instances) obj.instances = []; - for (var i = 0; i < obj.instances.length; ++i) { - var cur = obj.instances[i]; - if (cur.ctor == ctor) return cur.instance; - } - var instance = new Obj(obj, ctor && ctor.name); - instance.origin = obj.origin; - obj.instances.push({ctor: ctor, instance: instance}); - return instance; - }; - - var IsProto = exports.IsProto = constraint({ - construct: function(ctor, target) { - this.ctor = ctor; this.target = target; - }, - addType: function(o, _weight) { - if (!(o instanceof Obj)) return; - if ((this.count = (this.count || 0) + 1) > 8) return; - if (o == cx.protos.Array) - this.target.addType(new Arr); - else - this.target.addType(getInstance(o, this.ctor)); - } - }); - - var FnPrototype = constraint({ - construct: function(fn) { this.fn = fn; }, - addType: function(o, _weight) { - if (o instanceof Obj && !o.hasCtor) { - o.hasCtor = this.fn; - var adder = new SpeculativeThis(o, this.fn); - adder.addType(this.fn); - o.forAllProps(function(_prop, val, local) { - if (local) val.propagate(adder); - }); - } - } - }); - - var IsAdded = constraint({ - construct: function(other, target) { - this.other = other; this.target = target; - }, - addType: function(type, weight) { - if (type == cx.str) - this.target.addType(cx.str, weight); - else if (type == cx.num && this.other.hasType(cx.num)) - this.target.addType(cx.num, weight); - }, - typeHint: function() { return this.other; } - }); - - var IfObj = exports.IfObj = constraint({ - construct: function(target) { this.target = target; }, - addType: function(t, weight) { - if (t instanceof Obj) this.target.addType(t, weight); - }, - propagatesTo: function() { return this.target; } - }); - - var SpeculativeThis = constraint({ - construct: function(obj, ctor) { this.obj = obj; this.ctor = ctor; }, - addType: function(tp) { - if (tp instanceof Fn && tp.self) - tp.self.addType(getInstance(this.obj, this.ctor), WG_SPECULATIVE_PROTO_THIS); - } - }); - - var HasProto = constraint({ - construct: function(obj) { this.obj = obj }, - addType: function(tp) { - if (tp instanceof Obj && this.obj.proto == cx.protos.Object) - this.obj.replaceProto(tp); - } - }); - - var Muffle = constraint({ - construct: function(inner, weight) { - this.inner = inner; this.weight = weight; - }, - addType: function(tp, weight) { - this.inner.addType(tp, Math.min(weight, this.weight)); - }, - propagatesTo: function() { return this.inner.propagatesTo(); }, - typeHint: function() { return this.inner.typeHint(); }, - propHint: function() { return this.inner.propHint(); } - }); - - // TYPE OBJECTS - - var Type = exports.Type = function() {}; - Type.prototype = extend(ANull, { - constructor: Type, - propagate: function(c, w) { c.addType(this, w); }, - hasType: function(other) { return other == this; }, - isEmpty: function() { return false; }, - typeHint: function() { return this; }, - getType: function() { return this; } - }); - - var Prim = exports.Prim = function(proto, name) { this.name = name; this.proto = proto; }; - Prim.prototype = extend(Type.prototype, { - constructor: Prim, - toString: function() { return this.name; }, - getProp: function(prop) {return this.proto.hasProp(prop) || ANull;}, - gatherProperties: function(f, depth) { - if (this.proto) this.proto.gatherProperties(f, depth); - } - }); - - function isInteger(str) { - var c0 = str.charCodeAt(0); - if (c0 >= 48 && c0 <= 57) return !/\D/.test(str); - else return false; - } - - var Obj = exports.Obj = function(proto, name) { - if (!this.props) this.props = Object.create(null); - this.proto = proto === true ? cx.protos.Object : proto; - if (proto && proto != cx.protos.Object && !name && proto.name && !(this instanceof Fn)) { - var match = /^(.*)\.prototype$/.exec(this.proto.name); - if (match) name = match[1]; - } - this.name = name; - this.maybeProps = null; - this.origin = cx.curOrigin; - }; - Obj.prototype = extend(Type.prototype, { - constructor: Obj, - toString: function(maxDepth) { - if (maxDepth == null) maxDepth = 0; - if (maxDepth <= 0 && this.name) return this.name; - var props = [], etc = false; - for (var prop in this.props) if (prop != "") { - if (props.length > 5) { etc = true; break; } - if (maxDepth) - props.push(prop + ": " + toString(this.props[prop], maxDepth - 1, this)); - else - props.push(prop); - } - props.sort(); - if (etc) props.push("..."); - return "{" + props.join(", ") + "}"; - }, - hasProp: function(prop, searchProto) { - if (isInteger(prop)) prop = this.normalizeIntegerProp(prop); - var found = this.props[prop]; - if (searchProto !== false) - for (var p = this.proto; p && !found; p = p.proto) found = p.props[prop]; - return found; - }, - defProp: function(prop, originNode) { - var found = this.hasProp(prop, false); - if (found) { - if (originNode && !found.originNode) found.originNode = originNode; - return found; - } - if (ignoredProp(prop)) return ANull; - if (isInteger(prop)) prop = this.normalizeIntegerProp(prop); - - var av = this.maybeProps && this.maybeProps[prop]; - if (av) { - delete this.maybeProps[prop]; - this.maybeUnregProtoPropHandler(); - } else { - av = new AVal; - av.propertyOf = this; - av.propertyName = prop; - } - - this.props[prop] = av; - av.originNode = originNode; - av.origin = cx.curOrigin; - this.broadcastProp(prop, av, true); - return av; - }, - getProp: function(prop) { - var found = this.hasProp(prop, true) || (this.maybeProps && this.maybeProps[prop]); - if (found) return found; - if (ignoredProp(prop)) return ANull; - if (isInteger(prop)) prop = this.normalizeIntegerProp(prop); - var av = this.ensureMaybeProps()[prop] = new AVal; - av.propertyOf = this; - av.propertyName = prop; - return av; - }, - normalizeIntegerProp: function(_) { return "" }, - broadcastProp: function(prop, val, local) { - if (local) { - this.signal("addProp", prop, val); - // If this is a scope, it shouldn't be registered - if (!(this instanceof Scope)) registerProp(prop, this); - } - - if (this.onNewProp) for (var i = 0; i < this.onNewProp.length; ++i) { - var h = this.onNewProp[i]; - h.onProtoProp ? h.onProtoProp(prop, val, local) : h(prop, val, local); - } - }, - onProtoProp: function(prop, val, _local) { - var maybe = this.maybeProps && this.maybeProps[prop]; - if (maybe) { - delete this.maybeProps[prop]; - this.maybeUnregProtoPropHandler(); - this.proto.getProp(prop).propagate(maybe); - } - this.broadcastProp(prop, val, false); - }, - replaceProto: function(proto) { - for (var o = proto; o; o = o.proto) - if (o == this) return; - if (this.proto && this.maybeProps) - this.proto.unregPropHandler(this); - this.proto = proto; - if (this.maybeProps) - this.proto.forAllProps(this); - }, - ensureMaybeProps: function() { - if (!this.maybeProps) { - if (this.proto) this.proto.forAllProps(this); - this.maybeProps = Object.create(null); - } - return this.maybeProps; - }, - removeProp: function(prop) { - var av = this.props[prop]; - delete this.props[prop]; - this.ensureMaybeProps()[prop] = av; - av.types.length = 0; - }, - forAllProps: function(c) { - if (!this.onNewProp) { - this.onNewProp = []; - if (this.proto) this.proto.forAllProps(this); - } - this.onNewProp.push(c); - for (var o = this; o; o = o.proto) for (var prop in o.props) { - if (c.onProtoProp) - c.onProtoProp(prop, o.props[prop], o == this); - else - c(prop, o.props[prop], o == this); - } - }, - maybeUnregProtoPropHandler: function() { - if (this.maybeProps) { - for (var _n in this.maybeProps) return; - this.maybeProps = null; - } - if (!this.proto || this.onNewProp && this.onNewProp.length) return; - this.proto.unregPropHandler(this); - }, - unregPropHandler: function(handler) { - for (var i = 0; i < this.onNewProp.length; ++i) - if (this.onNewProp[i] == handler) { this.onNewProp.splice(i, 1); break; } - this.maybeUnregProtoPropHandler(); - }, - gatherProperties: function(f, depth) { - for (var prop in this.props) if (prop != "" && prop.charAt(0) != ":") - f(prop, this, depth); - if (this.proto) this.proto.gatherProperties(f, depth + 1); - }, - getObjType: function() { return this; } - }); - - var geckoIterators = typeof StopIteration != "undefined"; - function ignoredProp(name) { - return name == "__proto__" || name == "✖" || geckoIterators && name == "__iterator__"; - } - - var Fn = exports.Fn = function(name, self, args, argNames, retval, generator, async) { - Obj.call(this, cx.protos.Function, name); - this.self = self; - this.args = args; - this.argNames = argNames; - this.retval = retval; - this.generator = generator; - this.async = async; - }; - Fn.prototype = extend(Obj.prototype, { - constructor: Fn, - toString: function(maxDepth) { - if (maxDepth == null) maxDepth = 0; - var str = this.generator ? "fn*(" : "fn("; - for (var i = 0; i < this.args.length; ++i) { - if (i) str += ", "; - var name = this.argNames[i]; - if (name && name != "?") str += name + ": "; - str += maxDepth > -3 ? toString(this.args[i], maxDepth - 1, this) : "?"; - } - str += ")"; - if (!this.retval.isEmpty()) - str += " -> " + (maxDepth > -3 ? toString(this.retval, maxDepth - 1, this) : "?"); - return str; - }, - getProp: function(prop) { - if (prop == "prototype") { - var known = this.hasProp(prop, false); - if (!known) { - known = this.defProp(prop); - var proto = new Obj(true, this.name && this.name + ".prototype"); - proto.origin = this.origin; - known.addType(proto, WG_MADEUP_PROTO); - } - return known; - } - return Obj.prototype.getProp.call(this, prop); - }, - defProp: function(prop, originNode) { - if (prop == "prototype") { - var found = this.hasProp(prop, false); - if (found) return found; - found = Obj.prototype.defProp.call(this, prop, originNode); - found.origin = this.origin; - found.propagate(new FnPrototype(this)); - return found; - } - return Obj.prototype.defProp.call(this, prop, originNode); - }, - getFunctionType: function() { return this; }, - isArrowFn: function() { return this.originNode && this.originNode.type == "ArrowFunctionExpression" } - }); - - var Arr = exports.Arr = function(contentType) { - Obj.call(this, cx.protos.Array); - var content = this.defProp(""); - if (Array.isArray(contentType)) { - this.tuple = contentType.length; - for (var i = 0; i < contentType.length; i++) { - var prop = this.defProp(String(i)); - contentType[i].propagate(prop); - prop.propagate(content); - } - } else if (contentType) { - this.tuple = 0; - contentType.propagate(content); - } - }; - Arr.prototype = extend(Obj.prototype, { - constructor: Arr, - toString: function(maxDepth) { - if (maxDepth == null) maxDepth = 0; - if (maxDepth <= -3) return "[?]"; - var content = ""; - if (this.tuple) { - var similar; - for (var i = 0; i in this.props; i++) { - var type = toString(this.getProp(String(i)), maxDepth - 1, this); - if (similar == null) - similar = type; - else if (similar != type) - similar = false; - else - similar = type; - content += (content ? ", " : "") + type; - } - if (similar) content = similar; - } else { - content = toString(this.getProp(""), maxDepth - 1, this); - } - return "[" + content + "]"; - }, - normalizeIntegerProp: function(prop) { - if (+prop < this.tuple) return prop; - else return ""; - } - }); - - var Sym = exports.Sym = function(name, originNode) { - Prim.call(this, cx.protos.Symbol, "Symbol"); - this.symName = name; - this.originNode = originNode; - }; - Sym.prototype = extend(Prim.prototype, { - constructor: Sym, - asPropName: function() { return ":" + this.symName }, - getSymbolType: function() { return this } - }); - - exports.getSymbol = function(name, originNode) { - var cleanName = name.replace(/[^\w$\.]/g, "_"); - var known = cx.symbols[cleanName]; - if (known) { - if (originNode && !known.originNode) known.originNode = originNode; - return known; - } - return cx.symbols[cleanName] = new Sym(cleanName, originNode); - }; - - // THE PROPERTY REGISTRY - - function registerProp(prop, obj) { - var data = cx.props[prop] || (cx.props[prop] = []); - data.push(obj); - } - - function objsWithProp(prop) { - return cx.props[prop]; - } - - // INFERENCE CONTEXT - - exports.Context = function(defs, parent) { - this.parent = parent; - this.props = Object.create(null); - this.protos = Object.create(null); - this.origins = []; - this.curOrigin = "ecmascript"; - this.paths = Object.create(null); - this.definitions = Object.create(null); - this.purgeGen = 0; - this.workList = null; - this.disabledComputing = null; - this.curSuperCtor = this.curSuper = null; - this.symbols = Object.create(null); - - exports.withContext(this, function() { - cx.protos.Object = new Obj(null, "Object.prototype"); - cx.topScope = new Scope(); - cx.topScope.name = ""; - cx.protos.Array = new Obj(true, "Array.prototype"); - cx.protos.Function = new Fn("Function.prototype", ANull, [], [], ANull); - cx.protos.Function.proto = cx.protos.Object; - cx.protos.RegExp = new Obj(true, "RegExp.prototype"); - cx.protos.String = new Obj(true, "String.prototype"); - cx.protos.Number = new Obj(true, "Number.prototype"); - cx.protos.Boolean = new Obj(true, "Boolean.prototype"); - cx.protos.Symbol = new Obj(true, "Symbol.prototype"); - cx.str = new Prim(cx.protos.String, "string"); - cx.bool = new Prim(cx.protos.Boolean, "bool"); - cx.num = new Prim(cx.protos.Number, "number"); - cx.curOrigin = null; - - if (defs) for (var i = 0; i < defs.length; ++i) - def.load(defs[i]); - }); - }; - - exports.Context.prototype.startAnalysis = function() { - this.disabledComputing = this.workList = this.curSuperCtor = this.curSuper = null; - }; - - var cx = null; - exports.cx = function() { return cx; }; - - exports.withContext = function(context, f) { - var old = cx; - cx = context; - try { return f(); } - finally { cx = old; } - }; - - exports.TimedOut = function() { - this.message = "Timed out"; - this.stack = (new Error()).stack; - }; - exports.TimedOut.prototype = Object.create(Error.prototype); - exports.TimedOut.prototype.name = "infer.TimedOut"; - - var timeout; - exports.withTimeout = function(ms, f) { - var end = +new Date + ms; - var oldEnd = timeout; - if (oldEnd && oldEnd < end) return f(); - timeout = end; - try { return f(); } - finally { timeout = oldEnd; } - }; - - exports.addOrigin = function(origin) { - if (cx.origins.indexOf(origin) < 0) cx.origins.push(origin); - }; - - var baseMaxWorkDepth = 20, reduceMaxWorkDepth = 0.0001; - function withWorklist(f) { - if (cx.workList) return f(cx.workList); - - var list = [], depth = 0; - var add = cx.workList = function(type, target, weight) { - if (depth < baseMaxWorkDepth - reduceMaxWorkDepth * list.length) - list.push(type, target, weight, depth); - }; - var ret = f(add); - for (var i = 0; i < list.length; i += 4) { - if (timeout && +new Date >= timeout) - throw new exports.TimedOut(); - depth = list[i + 3] + 1; - list[i + 1].addType(list[i], list[i + 2]); - } - cx.workList = null; - return ret; - } - - function withSuper(ctor, obj, f) { - var oldCtor = cx.curSuperCtor, oldObj = cx.curSuper; - cx.curSuperCtor = ctor; cx.curSuper = obj; - var result = f(); - cx.curSuperCtor = oldCtor; cx.curSuper = oldObj; - return result; - } - - // SCOPES - - var Scope = exports.Scope = function(prev, originNode, isBlock, isCatch) { - Obj.call(this, prev || true); - this.prev = prev; - this.originNode = originNode; - this.isBlock = !!isBlock; - this.isCatch = !!isCatch; - }; - Scope.prototype = extend(Obj.prototype, { - constructor: Scope, - defVar: function(name, originNode) { - for (var s = this; ; s = s.proto) { - var found = s.props[name]; - if (found) return found; - if (!s.prev) return s.defProp(name, originNode); - } - } - }); - - function functionScope(scope, arrow) { - while (scope.isBlock || scope.isCatch || (arrow === false && scope.fnType && scope.fnType.isArrowFn())) - scope = scope.prev; - return scope; - } - - - // RETVAL COMPUTATION HEURISTICS - - function maybeInstantiate(scope, score) { - var fn = functionScope(scope).fnType; - if (fn) fn.instantiateScore = (fn.instantiateScore || 0) + score; - } - - var NotSmaller = {}; - function nodeSmallerThan(node, n) { - try { - walk.simple(node, {Expression: function() { if (--n <= 0) throw NotSmaller; }}); - return true; - } catch(e) { - if (e == NotSmaller) return false; - throw e; - } - } - - function maybeTagAsInstantiated(node, fn) { - var score = fn.instantiateScore; - if (!cx.disabledComputing && score && fn.args.length && nodeSmallerThan(node, score * 5)) { - maybeInstantiate(functionScope(fn.originNode.scope.prev), score / 2); - setFunctionInstantiated(node, fn); - return true; - } else { - fn.instantiateScore = null; - } - } - - function setFunctionInstantiated(node, fn) { - // Disconnect the arg avals, so that we can add info to them without side effects - var refScope = node.scope; - for (var i = 0; i < fn.args.length; ++i) fn.args[i] = new AVal; - fn.self = new AVal; - fn.computeRet = function(self, args) { - // Prevent recursion - return withDisabledComputing(fn, function() { - var oldOrigin = cx.curOrigin; - cx.curOrigin = fn.origin; - var scope = node.scope ? node.scope : refScope; - var scopeCopy = new Scope(scope.prev, scope.originNode); - for (var v in scope.props) { - var local = scopeCopy.defProp(v, scope.props[v].originNode); - for (var i = 0; i < args.length; ++i) if (fn.argNames[i] == v && i < args.length) - args[i].propagate(local); - } - var argNames = fn.argNames.length != args.length ? fn.argNames.slice(0, args.length) : fn.argNames; - while (argNames.length < args.length) argNames.push("?"); - scopeCopy.fnType = new Fn(fn.name, self, args, argNames, ANull, fn.generator, fn.async); - scopeCopy.fnType.originNode = fn.originNode; - if (fn.arguments) { - var argset = scopeCopy.fnType.arguments = new AVal; - scopeCopy.defProp("arguments").addType(new Arr(argset)); - for (var i = 0; i < args.length; ++i) args[i].propagate(argset); - } - node.scope = scopeCopy; - walk.recursive(node.body, scopeCopy, null, scopeGatherer); - walk.recursive(node.body, scopeCopy, null, inferWrapper); - cx.curOrigin = oldOrigin; - return scopeCopy.fnType.retval; - }); - }; - } - - function maybeTagAsGeneric(fn) { - var target = fn.retval; - if (target == ANull || fn.isArrowFn()) return; - var targetInner, asArray; - if (!target.isEmpty() && (targetInner = target.getType()) instanceof Arr) - target = asArray = targetInner.getProp(""); - - function explore(aval, path, depth) { - if (depth > 3 || !aval.forward) return; - for (var i = 0; i < aval.forward.length; ++i) { - var prop = aval.forward[i].propagatesTo(); - if (!prop) continue; - var newPath = path, dest; - if (prop instanceof AVal) { - dest = prop; - } else if (prop.target instanceof AVal) { - newPath += prop.pathExt; - dest = prop.target; - } else continue; - if (dest == target) return newPath; - var found = explore(dest, newPath, depth + 1); - if (found) return found; - } - } - - var foundPath = explore(fn.self, "!this", 0); - for (var i = 0; !foundPath && i < fn.args.length; ++i) - foundPath = explore(fn.args[i], "!" + i, 0); - - if (foundPath) { - if (asArray) foundPath = "[" + foundPath + "]"; - var p = new def.TypeParser(foundPath); - var parsed = p.parseType(true); - fn.computeRet = parsed.apply ? parsed : function() { return parsed; }; - fn.computeRetSource = foundPath; - return true; - } - } - - // SCOPE GATHERING PASS - - function addVar(scope, nameNode) { - return scope.defProp(nameNode.name, nameNode); - } - function patternName(node) { - if (node.type == "Identifier") return node.name; - if (node.type == "AssignmentPattern") return patternName(node.left); - if (node.type == "ObjectPattern") return "{" + node.properties.map(function(e) { return patternName(e.type === 'RestElement' ? e : e.value) }).join(", ") + "}"; - if (node.type == "ArrayPattern") return "[" + node.elements.map(function(e) { return e ? patternName(e) : "" }).join(", ") + "]"; - if (node.type == "RestElement") return "..." + patternName(node.argument); - return "_"; - } - - function isBlockScopedDecl(node) { - return node.type == "VariableDeclaration" && node.kind != "var" || - node.type == "FunctionDeclaration" || - node.type == "ClassDeclaration"; - } - - function patternScopes(inner, outer) { - return {inner: inner, outer: outer || inner}; - } - - var scopeGatherer = exports.scopeGatherer = walk.make({ - VariablePattern: function(node, scopes) { - if (scopes.inner) addVar(scopes.inner, node); - }, - AssignmentPattern: function(node, scopes, c) { - c(node.left, scopes, "Pattern"); - c(node.right, scopes.outer, "Expression"); - }, - AssignmentExpression: function(node, scope, c) { - if (node.left.type == "MemberExpression") - c(node.left, scope, "Expression"); - else - c(node.left, patternScopes(false, scope), "Pattern"); - c(node.right, scope, "Expression"); - }, - MemberPattern: function(node, scope, c) { - c(node, scope.outer); - }, - Function: function(node, scope, c) { - var inner = node.scope = new Scope(scope, node); - var argVals = [], argNames = []; - for (var i = 0; i < node.params.length; ++i) { - var param = node.params[i]; - argNames.push(patternName(param)); - if (param.type == "Identifier") { - argVals.push(addVar(inner, param)); - } else { - var arg = new AVal; - argVals.push(arg); - arg.originNode = param; - c(param, patternScopes(inner), "Pattern"); - } - } - inner.fnType = new Fn(node.id && node.id.name, new AVal, argVals, argNames, ANull, node.generator, node.async); - inner.fnType.originNode = node; - if (node.id) { - var decl = node.type == "FunctionDeclaration"; - addVar(decl ? scope : inner, node.id); - } - c(node.body, inner, node.expression ? "Expression" : "Statement"); - }, - BlockStatement: function(node, scope, c) { - if (!node.scope && node.body.some(isBlockScopedDecl)) - scope = node.scope = new Scope(scope, node, true); - walk.base.BlockStatement(node, scope, c); - }, - CatchClause: function(node, scope, c) { - scope = node.scope = new Scope(scope, node, false, true); - if (node.param.type == "Identifier") { - var v = addVar(scope, node.param); - c(node.body, scope, "Statement"); - var ecma = cx.definitions.ecmascript; - if (ecma && v.isEmpty()) getInstance(ecma["Error.prototype"]).propagate(v, WG_CATCH_ERROR); - } else { - c(node.param, patternScopes(scope), "Pattern"); - } - }, - VariableDeclaration: function(node, scope, c) { - var targetScope = node.kind == "var" ? functionScope(scope) : scope; - for (var i = 0; i < node.declarations.length; ++i) { - var decl = node.declarations[i]; - c(decl.id, patternScopes(targetScope, scope), "Pattern"); - if (decl.init) c(decl.init, scope, "Expression"); - } - }, - ClassDeclaration: function(node, scope, c) { - if (node.id) addVar(scope, node.id); - if (node.superClass) c(node.superClass, scope, "Expression"); - for (var i = 0; i < node.body.body.length; i++) - c(node.body.body[i], scope); - }, - ForInStatement: function(node, scope, c) { - if (!node.scope && isBlockScopedDecl(node.left)) - scope = node.scope = new Scope(scope, node, true); - walk.base.ForInStatement(node, scope, c); - }, - ForStatement: function(node, scope, c) { - if (!node.scope && node.init && isBlockScopedDecl(node.init)) - scope = node.scope = new Scope(scope, node, true); - walk.base.ForStatement(node, scope, c); - }, - ImportDeclaration: function(node, scope) { - for (var i = 0; i < node.specifiers.length; i++) - addVar(scope, node.specifiers[i].local); - } - }); - scopeGatherer.ForOfStatement = scopeGatherer.ForInStatement; - - function rmScope(node) { if (node.scope) node.scope = null } - var scopeClearer = {BlockStatement: rmScope, Function: rmScope, CatchClause: rmScope, - ForInStateMent: rmScope, ForStatement: rmScope}; - exports.clearScopes = function(ast) { - walk.simple(ast, scopeClearer); - }; - - // CONSTRAINT GATHERING PASS - - var propName = exports.propName = function(node, inferInScope) { - var key = node.property || node.key; - if (!node.computed && key.type == "Identifier") return key.name; - if (key.type == "Literal") { - if (typeof key.value == "string") return key.value; - if (typeof key.value == "number") return String(key.value); - } - if (inferInScope) { - var symName = symbolName(infer(key, inferInScope)); - if (symName) return node.propName = symName; - } else if (node.propName) { - return node.propName; - } - return ""; - }; - function symbolName(val) { - var sym = val.getSymbolType(); - if (sym) return sym.asPropName(); - } - - function unopResultType(op) { - switch (op) { - case "+": case "-": case "~": return cx.num; - case "!": return cx.bool; - case "typeof": return cx.str; - case "void": case "delete": return ANull; - } - } - function binopIsBoolean(op) { - switch (op) { - case "==": case "!=": case "===": case "!==": case "<": case ">": case ">=": case "<=": - case "in": case "instanceof": return true; - } - } - function literalType(node) { - if (node.regex) return getInstance(cx.protos.RegExp); - switch (typeof node.value) { - case "boolean": return cx.bool; - case "number": return cx.num; - case "string": return cx.str; - case "object": - case "function": - if (!node.value) return ANull; - return getInstance(cx.protos.RegExp); - } - } - - function join(a, b) { - if (a == b || b == ANull) return a; - if (a == ANull) return b; - var joined = new AVal; - a.propagate(joined); - b.propagate(joined); - return joined; - } - - function connectParams(node, scope) { - for (var i = 0; i < node.params.length; i++) { - var param = node.params[i]; - if (param.type == "Identifier") continue; - connectPattern(param, scope, node.scope.fnType.args[i]); - } - } - - function ensureVar(node, scope) { - return scope.hasProp(node.name) || cx.topScope.defProp(node.name, node); - } - - var inferPatternVisitor = exports.inferPatternVisitor = { - Identifier: function(node, scope, source) { - source.propagate(ensureVar(node, scope)); - }, - MemberExpression: function(node, scope, source) { - var obj = infer(node.object, scope); - var pName = propName(node, scope); - obj.propagate(new DefProp(pName, source, node.property)); - }, - RestElement: function(node, scope, source) { - connectPattern(node.argument, scope, new Arr(source)); - }, - ObjectPattern: function(node, scope, source) { - for (var i = 0; i < node.properties.length; ++i) { - var prop = node.properties[i]; - if (prop.type == 'RestElement') { continue; } - connectPattern(prop.value, scope, source.getProp(propName(prop))); - } - }, - ArrayPattern: function(node, scope, source) { - for (var i = 0; i < node.elements.length; i++) - if (node.elements[i]) - connectPattern(node.elements[i], scope, source.getProp(String(i))); - }, - AssignmentPattern: function(node, scope, source) { - connectPattern(node.left, scope, join(source, infer(node.right, scope))); - } - }; - - function connectPattern(node, scope, source) { - var connecter = inferPatternVisitor[node.type]; - if (connecter) connecter(node, scope, source); - } - - function getThis(scope) { - var fnScope = functionScope(scope); - return fnScope.fnType ? fnScope.fnType.self : fnScope; - } - - function maybeAddPhantomObj(obj) { - if (!obj.isEmpty() || !obj.propertyOf) return; - obj.propertyOf.getProp(obj.propertyName).addType(new Obj, WG_PHANTOM_OBJ); - maybeAddPhantomObj(obj.propertyOf); - } - - function inferClass(node, scope, name) { - if (!name && node.id) name = node.id.name; - - var sup = cx.protos.Object, supCtor, delayed; - if (node.superClass) { - if (node.superClass.type == "Literal" && node.superClass.value == null) { - sup = null; - } else { - var supVal = infer(node.superClass, scope), supProto; - supCtor = supVal.getFunctionType(); - if (supCtor && (supProto = supCtor.getProp("prototype").getObjType())) { - sup = supProto; - } else { - supCtor = supVal; - delayed = supVal.getProp("prototype"); - } - } - } - var proto = new Obj(sup, name && name + ".prototype"); - if (delayed) delayed.propagate(new HasProto(proto)); - - return withSuper(supCtor, delayed || sup, function() { - var ctor, body = node.body.body; - for (var i = 0; i < body.length; i++) - if (body[i].kind == "constructor") ctor = body[i].value; - var fn = node.objType = ctor ? infer(ctor, scope) : new Fn(name, ANull, [], null, ANull); - fn.originNode = node.id || ctor || node; - - var inst = getInstance(proto, fn); - fn.self.addType(inst); - fn.defProp("prototype", node).addType(proto); - for (var i = 0; i < body.length; i++) { - var method = body[i], target; - if (method.kind == "constructor") continue; - var pName = propName(method, scope); - if (pName == "" || method.kind == "set") { - target = ANull; - } else { - target = (method.static ? fn : proto).defProp(pName, method.key); - target.initializer = true; - if (method.kind == "get") target = new IsCallee(inst, [], null, target); - } - infer(method.value, scope, target); - var methodFn = target.getFunctionType(); - if (methodFn) methodFn.self.addType(inst); - } - return fn; - }); - } - - function arrayLiteralType(elements, scope, inner) { - var tuple = elements.length > 1 && elements.length < 6; - if (tuple) { - var homogenous = true, litType; - for (var i = 0; i < elements.length; i++) { - var elt = elements[i]; - if (!elt) - tuple = false; - else if (elt.type != "Literal" || (litType && litType != typeof elt.value)) - homogenous = false; - else - litType = typeof elt.value; - } - if (homogenous) tuple = false; - } - - if (tuple) { - var types = []; - for (var i = 0; i < elements.length; ++i) - types.push(inner(elements[i], scope)); - return new Arr(types); - } else if (elements.length < 2) { - return new Arr(elements[0] && inner(elements[0], scope)); - } else { - var eltVal = new AVal; - for (var i = 0; i < elements.length; i++) - if (elements[i]) inner(elements[i], scope).propagate(eltVal); - return new Arr(eltVal); - } - } - - function ret(f) { - return function(node, scope, out, name) { - var r = f(node, scope, name); - if (out) r.propagate(out); - return r; - }; - } - function fill(f) { - return function(node, scope, out, name) { - if (!out) out = new AVal; - f(node, scope, out, name); - return out; - }; - } - - var inferExprVisitor = exports.inferExprVisitor = { - ArrayExpression: ret(function(node, scope) { - return arrayLiteralType(node.elements, scope, infer); - }), - ObjectExpression: ret(function(node, scope, name) { - var proto = cx.protos.Object, waitForProto; - for (var i = 0; i < node.properties.length; ++i) { - var prop = node.properties[i]; - if (prop.type == 'SpreadElement') { continue; } - if (prop.key.name == "__proto__") { - if (prop.value.type == "Literal" && prop.value.value == null) { - proto = null; - } else { - var protoVal = infer(prop.value, scope), known = protoVal.getObjType(); - if (known) proto = known; - else waitForProto = protoVal; - } - } - } - - var obj = node.objType = new Obj(proto, name); - if (waitForProto) waitForProto.propagate(new HasProto(obj)); - obj.originNode = node; - - withSuper(null, waitForProto || proto, function() { - for (var i = 0; i < node.properties.length; ++i) { - var prop = node.properties[i], key = prop.key; - if (prop.type == 'SpreadElement' || ignoredProp(prop.key.name)) continue; - - var name = propName(prop, scope), target; - if (name == "" || prop.kind == "set") { - target = ANull; - } else { - target = obj.defProp(name, key); - var val = target; - val.initializer = true; - if (prop.kind == "get") - target = new IsCallee(obj, [], null, val); - } - infer(prop.value, scope, target, name); - if (prop.value.type == "FunctionExpression") - prop.value.scope.fnType.self.addType(obj, WG_SPECULATIVE_THIS); - } - }); - return obj; - }), - FunctionExpression: ret(function(node, scope, name) { - var inner = node.scope, fn = inner.fnType; - if (name && !fn.name) fn.name = name; - connectParams(node, inner); - if (node.expression) - infer(node.body, inner, inner.fnType.retval = new AVal); - else - walk.recursive(node.body, inner, null, inferWrapper, "Statement"); - if (node.type == "ArrowFunctionExpression") - getThis(scope).propagate(fn.self); - maybeTagAsInstantiated(node, fn) || maybeTagAsGeneric(fn); - if (node.id) inner.getProp(node.id.name).addType(fn); - return fn; - }), - ClassExpression: ret(inferClass), - SequenceExpression: ret(function(node, scope) { - for (var i = 0, l = node.expressions.length - 1; i < l; ++i) - infer(node.expressions[i], scope, ANull); - return infer(node.expressions[l], scope); - }), - UnaryExpression: ret(function(node, scope) { - infer(node.argument, scope, ANull); - return unopResultType(node.operator); - }), - UpdateExpression: ret(function(node, scope) { - infer(node.argument, scope, ANull); - return cx.num; - }), - BinaryExpression: ret(function(node, scope) { - if (node.operator == "+") { - var lhs = infer(node.left, scope); - var rhs = infer(node.right, scope); - if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; - if (lhs.hasType(cx.num) && rhs.hasType(cx.num)) return cx.num; - var result = new AVal; - lhs.propagate(new IsAdded(rhs, result)); - rhs.propagate(new IsAdded(lhs, result)); - return result; - } else { - infer(node.left, scope, ANull); - infer(node.right, scope, ANull); - return binopIsBoolean(node.operator) ? cx.bool : cx.num; - } - }), - AssignmentExpression: ret(function(node, scope, name) { - var rhs, pName; - if (node.left.type == "MemberExpression") { - pName = propName(node.left, scope); - if (!name) - name = node.left.object.type == "Identifier" ? node.left.object.name + "." + pName : pName; - } else if (!name && node.left.type == "Identifier") { - name = node.left.name; - } - - if (node.operator && node.operator != "=" && node.operator != "+=") { - infer(node.right, scope, ANull); - rhs = cx.num; - } else { - rhs = infer(node.right, scope, null, name); - } - - if (node.left.type == "MemberExpression") { - var obj = infer(node.left.object, scope); - if (pName == "prototype") maybeInstantiate(scope, 20); - if (pName == "") { - // This is a hack to recognize for/in loops that copy - // properties, and do the copying ourselves, insofar as we - // manage, because such loops tend to be relevant for type - // information. - var v = node.left.property.name, local = scope.props[v], over = local && local.iteratesOver; - if (over) { - maybeInstantiate(scope, 20); - var fromRight = node.right.type == "MemberExpression" && node.right.computed && node.right.property.name == v; - over.forAllProps(function(prop, val, local) { - if (local && prop != "prototype" && prop != "") - obj.propagate(new DefProp(prop, fromRight ? val : ANull)); - }); - return rhs; - } - } - - obj.propagate(new DefProp(pName, rhs, node.left.property)); - maybeAddPhantomObj(obj); - if (node.right.type == "FunctionExpression") - obj.propagate(node.right.scope.fnType.self, WG_SPECULATIVE_THIS); - } else { - connectPattern(node.left, scope, rhs); - } - return rhs; - }), - LogicalExpression: fill(function(node, scope, out) { - infer(node.left, scope, out); - infer(node.right, scope, out); - }), - ConditionalExpression: fill(function(node, scope, out) { - infer(node.test, scope, ANull); - infer(node.consequent, scope, out); - infer(node.alternate, scope, out); - }), - NewExpression: fill(function(node, scope, out, name) { - if (node.callee.type == "Identifier" && node.callee.name in scope.props) - maybeInstantiate(scope, 20); - - for (var i = 0, args = []; i < node.arguments.length; ++i) - args.push(infer(node.arguments[i], scope)); - var callee = infer(node.callee, scope); - var self = new AVal; - callee.propagate(new IsCtor(self, name && /\.prototype$/.test(name))); - self.propagate(out, WG_NEW_INSTANCE); - callee.propagate(new IsCallee(self, args, node.arguments, new IfObj(out))); - }), - CallExpression: fill(function(node, scope, out) { - for (var i = 0, args = []; i < node.arguments.length; ++i) - args.push(infer(node.arguments[i], scope)); - var outerFn = functionScope(scope).fnType; - if (node.callee.type == "MemberExpression") { - var self = infer(node.callee.object, scope); - var pName = propName(node.callee, scope); - if (outerFn && (pName == "call" || pName == "apply") && - outerFn.args.indexOf(self) > -1) - maybeInstantiate(scope, 30); - self.propagate(new HasMethodCall(pName, args, node.arguments, out)); - } else if (node.callee.type == "Super" && cx.curSuperCtor) { - node.callee.superType = cx.curSuperCtor; - cx.curSuperCtor.propagate(new IsCallee(getThis(scope), args, node.arguments, out)); - getThis(scope).propagate(out, WG_NEW_INSTANCE); - } else { - var callee = infer(node.callee, scope); - if (outerFn && outerFn.args.indexOf(callee) > -1) - maybeInstantiate(scope, 30); - var knownFn = callee.getFunctionType(); - if (knownFn && knownFn.instantiateScore && outerFn) - maybeInstantiate(scope, knownFn.instantiateScore / 5); - callee.propagate(new IsCallee(cx.topScope, args, node.arguments, out)); - } - }), - AwaitExpression: fill(function(node, scope, out, name) { - var arg = infer(node.argument, scope, null, name); - var tp = arg.getType(); - if (tp && tp.constructor == Obj && tp.name == "Promise") { - if (tp.hasProp(":t")) { - tp.getProp(":t").propagate(out); - } - } else { - arg.propagate(out); - } - }), - MemberExpression: fill(function(node, scope, out) { - var name = propName(node), wg; - if (name == "") { - var propType = infer(node.property, scope); - var symName = symbolName(propType); - if (symName) - name = node.propName = symName; - else if (!propType.hasType(cx.num)) - wg = WG_MULTI_MEMBER; - } - infer(node.object, scope).getProp(name).propagate(out, wg); - }), - Identifier: ret(function(node, scope) { - if (node.name == "arguments") { - var fnScope = functionScope(scope, false); - if (fnScope.fnType && !(node.name in fnScope.props)) - fnScope.defProp(node.name, fnScope.fnType.originNode) - .addType(new Arr(fnScope.fnType.arguments = new AVal)); - } - return scope.getProp(node.name); - }), - ThisExpression: ret(function(_node, scope) { - return getThis(scope); - }), - Super: ret(function(node) { - return node.superType = cx.curSuper || ANull; - }), - Literal: ret(function(node) { - return literalType(node); - }), - TemplateLiteral: ret(function(node, scope) { - for (var i = 0; i < node.expressions.length; ++i) - infer(node.expressions[i], scope, ANull); - return cx.str; - }), - TaggedTemplateExpression: fill(function(node, scope, out) { - var args = [new Arr(cx.str)]; - for (var i = 0; i < node.quasi.expressions.length; ++i) - args.push(infer(node.quasi.expressions[i], scope)); - infer(node.tag, scope, new IsCallee(cx.topScope, args, node.quasi.expressions, out)); - }), - YieldExpression: ret(function(node, scope) { - var output = ANull, fn = functionScope(scope).fnType; - if (fn) { - if (fn.retval == ANull) fn.retval = new AVal; - if (!fn.yieldval) fn.yieldval = new AVal; - output = fn.retval; - } - if (node.argument) { - if (node.delegate) { - infer(node.argument, scope, new HasMethodCall("next", [], null, - new GetProp("value", output))); - } else { - infer(node.argument, scope, output); - } - } - return fn ? fn.yieldval : ANull; - }) - }; - inferExprVisitor.ArrowFunctionExpression = inferExprVisitor.FunctionExpression; - - function infer(node, scope, out, name) { - var handler = inferExprVisitor[node.type]; - return handler ? handler(node, scope, out, name) : ANull; - } - - function loopPattern(init) { - return init.type == "VariableDeclaration" ? init.declarations[0].id : init; - } - - var inferWrapper = exports.inferWrapper = walk.make({ - Expression: function(node, scope) { - infer(node, node.scope || scope, ANull); - }, - - ObjectExpression: function(node, scope) { - infer(node, node.scope || scope, ANull); - }, - - FunctionDeclaration: function(node, scope, c) { - var inner = node.scope, fn = inner.fnType; - connectParams(node, inner); - c(node.body, inner, "Statement"); - maybeTagAsInstantiated(node, fn) || maybeTagAsGeneric(fn); - if (node.id) scope.getProp(node.id.name).addType(fn); - }, - - Statement: function(node, scope, c) { - c(node, node.scope || scope); - }, - - ExportDefaultDeclaration: function(node, scope, c) { - c(node.declaration, node.scope || scope); - }, - - VariableDeclaration: function(node, scope) { - for (var i = 0; i < node.declarations.length; ++i) { - var decl = node.declarations[i]; - if (decl.id.type == "Identifier") { - var prop = scope.getProp(decl.id.name); - if (decl.init) - infer(decl.init, scope, prop, decl.id.name); - } else if (decl.init) { - connectPattern(decl.id, scope, infer(decl.init, scope)); - } - } - }, - - ClassDeclaration: function(node, scope) { - if (!node.id) inferClass(node, scope); - else scope.getProp(node.id.name).addType(inferClass(node, scope, node.id.name)); - }, - - ReturnStatement: function(node, scope) { - if (!node.argument) return; - var output = ANull, fn = functionScope(scope).fnType; - if (fn) { - if (fn.retval == ANull) fn.retval = new AVal; - output = fn.retval; - } - infer(node.argument, scope, output); - }, - - ForInStatement: function(node, scope, c) { - var source = infer(node.right, scope); - if ((node.right.type == "Identifier" && node.right.name in scope.props) || - (node.right.type == "MemberExpression" && node.right.property.name == "prototype")) { - maybeInstantiate(scope, 5); - var pattern = loopPattern(node.left); - if (pattern.type == "Identifier") { - if (pattern.name in scope.props) - scope.getProp(pattern.name).iteratesOver = source; - source.getProp("").propagate(ensureVar(pattern, scope)); - } else { - connectPattern(pattern, scope, source.getProp("")); - } - } - c(node.body, scope, "Statement"); - }, - - ForOfStatement: function(node, scope, c) { - var pattern = loopPattern(node.left), target; - if (pattern.type == "Identifier") - target = ensureVar(pattern, scope); - else - connectPattern(pattern, scope, target = new AVal); - - if (node.await) { - infer(node.right, scope, new HasMethodCall(":Symbol.asyncIterator", [], null, - new HasMethodCall("next", [], null, - new GetProp(":t", - new GetProp("value", target))))); - } else { - infer(node.right, scope, new HasMethodCall(":Symbol.iterator", [], null, - new HasMethodCall("next", [], null, - new GetProp("value", target)))); - } - c(node.body, scope, "Statement"); - } - }); - - // PARSING - - var parse = exports.parse = function(text, options, thirdArg) { - if (!options || Array.isArray(options)) options = thirdArg; - var ast; - try { ast = acorn.parse(text, options); } - catch(e) { ast = acorn_loose.parse(text, options); } - return ast; - }; - - // ANALYSIS INTERFACE - - exports.analyze = function(ast, name, scope) { - if (typeof ast == "string") ast = parse(ast); - - if (!name) name = "file#" + cx.origins.length; - exports.addOrigin(cx.curOrigin = name); - - if (!scope) scope = cx.topScope; - cx.startAnalysis(); - - walk.recursive(ast, scope, null, scopeGatherer); - if (cx.parent) cx.parent.signal("preInfer", ast, scope); - walk.recursive(ast, scope, null, inferWrapper); - if (cx.parent) cx.parent.signal("postInfer", ast, scope); - - cx.curOrigin = null; - }; - - // PURGING - - exports.purge = function(origins, start, end) { - var test = makePredicate(origins, start, end); - ++cx.purgeGen; - cx.topScope.purge(test); - for (var prop in cx.props) { - var list = cx.props[prop]; - for (var i = 0; i < list.length; ++i) { - var obj = list[i], av = obj.props[prop]; - if (!av || test(av, av.originNode)) list.splice(i--, 1); - } - if (!list.length) delete cx.props[prop]; - } - }; - - function makePredicate(origins, start, end) { - var arr = Array.isArray(origins); - if (arr && origins.length == 1) { origins = origins[0]; arr = false; } - if (arr) { - if (end == null) return function(n) { return origins.indexOf(n.origin) > -1; }; - return function(n, pos) { return pos && pos.start >= start && pos.end <= end && origins.indexOf(n.origin) > -1; }; - } else { - if (end == null) return function(n) { return n.origin == origins; }; - return function(n, pos) { return pos && pos.start >= start && pos.end <= end && n.origin == origins; }; - } - } - - AVal.prototype.purge = function(test) { - if (this.purgeGen == cx.purgeGen) return; - this.purgeGen = cx.purgeGen; - for (var i = 0; i < this.types.length; ++i) { - var type = this.types[i]; - if (test(type, type.originNode)) - this.types.splice(i--, 1); - else - type.purge(test); - } - if (!this.types.length) this.maxWeight = 0; - - if (this.forward) for (var i = 0; i < this.forward.length; ++i) { - var f = this.forward[i]; - if (test(f)) { - this.forward.splice(i--, 1); - if (this.props) this.props = null; - } else if (f.purge) { - f.purge(test); - } - } - }; - ANull.purge = function() {}; - Obj.prototype.purge = function(test) { - if (this.purgeGen == cx.purgeGen) return true; - this.purgeGen = cx.purgeGen; - for (var p in this.props) { - var av = this.props[p]; - if (test(av, av.originNode)) - this.removeProp(p); - av.purge(test); - } - }; - Fn.prototype.purge = function(test) { - if (Obj.prototype.purge.call(this, test)) return; - this.self.purge(test); - this.retval.purge(test); - for (var i = 0; i < this.args.length; ++i) this.args[i].purge(test); - }; - - // EXPRESSION TYPE DETERMINATION - - function findByPropertyName(name) { - guessing = true; - var found = objsWithProp(name); - if (found) for (var i = 0; i < found.length; ++i) { - var val = found[i].getProp(name); - if (!val.isEmpty()) return val; - } - return ANull; - } - - function generatorResult(input, output, async) { - var defs = cx.definitions.ecmascript; - var valObj = new Obj(true); - valObj.defProp("done").addType(cx.bool); - output.propagate(valObj.defProp("value")); - var retObj = valObj; - if (async && defs) { - retObj = new Obj(defs["Promise.prototype"]); - retObj.getType().propagate(new DefProp(':t', valObj)); - } - var method = new Fn(null, ANull, input ? [input] : [], input ? ["?"] : [], retObj); - var result = new Obj(defs ? async ? defs.async_generator_prototype : defs.generator_prototype : true); - result.defProp("next").addType(method); - return result; - } - - function maybeIterator(fn, output) { - if (!fn.generator) return output; - if (!fn.computeRet) { // Reuse iterator objects for non-computed return types - if (fn.generator === true) fn.generator = generatorResult(fn.yieldval, output, fn.async); - return fn.generator; - } - return generatorResult(fn.yieldval, output, fn.async); - } - - function computeReturnType(funcNode, argNodes, scope) { - var fn = findType(funcNode, scope).getFunctionType(); - if (!fn) return ANull; - var result = fn.retval; - if (fn.computeRet) { - for (var i = 0, args = []; i < argNodes.length; ++i) - args.push(findType(argNodes[i], scope)); - var self = ANull; - if (funcNode.type == "MemberExpression") - self = findType(funcNode.object, scope); - result = fn.computeRet(self, args, argNodes); - } - return maybeIterator(fn, result); - } - - var typeFinder = exports.typeFinder = { - ArrayExpression: function(node, scope) { - return arrayLiteralType(node.elements, scope, findType); - }, - ObjectExpression: function(node) { - return node.objType; - }, - ClassDeclaration: function(node) { - return node.objType; - }, - ClassExpression: function(node) { - return node.objType; - }, - FunctionDeclaration: function(node) { - return node.scope.fnType; - }, - FunctionExpression: function(node) { - return node.scope.fnType; - }, - ArrowFunctionExpression: function(node) { - return node.scope.fnType; - }, - SequenceExpression: function(node, scope) { - return findType(node.expressions[node.expressions.length-1], scope); - }, - UnaryExpression: function(node) { - return unopResultType(node.operator); - }, - UpdateExpression: function() { - return cx.num; - }, - BinaryExpression: function(node, scope) { - if (binopIsBoolean(node.operator)) return cx.bool; - if (node.operator == "+") { - var lhs = findType(node.left, scope); - var rhs = findType(node.right, scope); - if (lhs.hasType(cx.str) || rhs.hasType(cx.str)) return cx.str; - } - return cx.num; - }, - AssignmentExpression: function(node, scope) { - return findType(node.right, scope); - }, - LogicalExpression: function(node, scope) { - var lhs = findType(node.left, scope); - return lhs.isEmpty() ? findType(node.right, scope) : lhs; - }, - ConditionalExpression: function(node, scope) { - var lhs = findType(node.consequent, scope); - return lhs.isEmpty() ? findType(node.alternate, scope) : lhs; - }, - NewExpression: function(node, scope) { - var f = findType(node.callee, scope).getFunctionType(); - var proto = f && f.getProp("prototype").getObjType(); - if (!proto) return ANull; - return getInstance(proto, f); - }, - CallExpression: function(node, scope) { - return computeReturnType(node.callee, node.arguments, scope); - }, - MemberExpression: function(node, scope) { - var propN = propName(node), obj = findType(node.object, scope).getType(); - if (obj) return obj.getProp(propN); - if (propN == "") return ANull; - return findByPropertyName(propN); - }, - MethodDefinition: function(node) { - var propN = propName(node), obj = getThis(node.value.scope).getType(); - if (obj) return obj.getProp(propN); - return ANull; - }, - Identifier: function(node, scope) { - return scope.hasProp(node.name) || ANull; - }, - ThisExpression: function(_node, scope) { - return getThis(scope); - }, - Literal: function(node) { - return literalType(node); - }, - Super: ret(function(node) { - return node.superType; - }), - TemplateLiteral: function() { - return cx.str; - }, - TaggedTemplateExpression: function(node, scope) { - return computeReturnType(node.tag, node.quasi.expressions, scope); - }, - YieldExpression: function(_node, scope) { - var fn = functionScope(scope).fnType; - return fn ? fn.yieldval : ANull; - } - }; - - function findType(node, scope) { - var finder = typeFinder[node.type]; - return finder ? finder(node, scope) : ANull; - } - - var searchVisitor = exports.searchVisitor = walk.make({ - Function: function(node, _st, c) { - walk.base.Function(node, node.scope, c); - }, - CatchClause: function(node, _st, c) { - walk.base.CatchClause(node, node.scope, c); - }, - Property: function(node, st, c) { - if (node.computed) c(node.key, st, "Expression"); - if (node.key != node.value) c(node.value, st, "Expression"); - }, - Statement: function(node, st, c) { - c(node, node.scope || st); - }, - ImportSpecifier: function(node, st, c) { - c(node.local, st); - }, - ImportDefaultSpecifier: function(node, st, c) { - c(node.local, st); - }, - ImportNamespaceSpecifier: function(node, st, c) { - c(node.local, st); - } - }); - var searchExprVisitor = exports.searchExprVisitor = walk.make({ - MemberExpression: function(node, st, c) { - c(node.object, st, "Expression"); - if (node.computed) { c(node.property, st, "Expression"); } - }, - Property: function(node, st, c) { - if (node.computed) c(node.key, st, "Expression"); - c(node.value, st, "Expression"); - } - }, searchVisitor); - exports.fullVisitor = walk.make({ - MemberExpression: function(node, st, c) { - c(node.object, st, "Expression"); - c(node.property, st, node.computed ? "Expression" : null); - }, - Property: function(node, st, c) { - if (node.computed) c(node.key, st, "Expression"); - c(node.value, st, "Expression"); - } - }, searchVisitor); - - exports.findExpressionAt = function(ast, start, end, defaultScope, filter) { - var test = filter || function(_t, node) { - if (node.type == "Identifier" && node.name == "✖") return false; - return typeFinder.hasOwnProperty(node.type); - }; - return walk.findNodeAt(ast, start, end, test, searchExprVisitor, defaultScope || cx.topScope); - }; - exports.findClosestExpression = function(ast, start, end, defaultScope, filter) { - var test = filter || function(_t, node) { - if (start != null && node.start > start) return false; - if (node.type == "Identifier" && node.name == "✖") return false; - return typeFinder.hasOwnProperty(node.type); - }; - return walk.findNodeAround(ast, end, test, searchExprVisitor, defaultScope || cx.topScope); - }; - - exports.findExpressionAround = function(ast, start, end, defaultScope, filter) { - var test = filter || function(_t, node) { - if (start != null && node.start > start) return false; - if (node.type == "Identifier" && node.name == "✖") return false; - return typeFinder.hasOwnProperty(node.type); - }; - return walk.findNodeAround(ast, end, test, searchVisitor, defaultScope || cx.topScope); - }; - - exports.expressionType = function(found) { - return findType(found.node, found.state); - }; - - // Finding the expected type of something, from context - - exports.parentNode = function(child, ast) { - var stack = []; - function c(node, st, override) { - if (node.start <= child.start && node.end >= child.end) { - var top = stack[stack.length - 1]; - if (node == child) throw {found: top}; - if (top != node) stack.push(node); - walk.base[override || node.type](node, st, c); - if (top != node) stack.pop(); - } - } - try { - c(ast, null); - } catch (e) { - if (e.found) return e.found; - throw e; - } - }; - - var findTypeFromContext = exports.findTypeFromContext = { - ArrayExpression: function(parent, _, get) { return get(parent, true).getProp(""); }, - ObjectExpression: function(parent, node, get) { - for (var i = 0; i < parent.properties.length; ++i) { - var prop = node.properties[i]; - if (prop.value == node) - return get(parent, true).getProp(propName(prop)); - } - }, - UnaryExpression: function(parent) { return unopResultType(parent.operator); }, - UpdateExpression: function() { return cx.num; }, - BinaryExpression: function(parent) { return binopIsBoolean(parent.operator) ? cx.bool : cx.num; }, - AssignmentExpression: function(parent, _, get) { return get(parent.left); }, - LogicalExpression: function(parent, _, get) { return get(parent, true); }, - ConditionalExpression: function(parent, node, get) { - if (parent.consequent == node || parent.alternate == node) return get(parent, true); - }, - CallExpression: function(parent, node, get) { - for (var i = 0; i < parent.arguments.length; i++) { - var arg = parent.arguments[i]; - if (arg == node) { - var calleeType = get(parent.callee).getFunctionType(); - if (calleeType instanceof Fn) - return calleeType.args[i]; - break; - } - } - }, - ReturnStatement: function(_parent, node, get) { - // tweaking search position to avoid endless recursion - // when looking for definition of key in fn ( return fn ( return object ) ) - // see ternjs/tern#777 - var fnNode = walk.findNodeAround(node.sourceFile.ast, node.start - 1, "Function"); - if (fnNode) { - var fnType = fnNode.node.type != "FunctionDeclaration" - ? get(fnNode.node, true).getFunctionType() - : fnNode.node.scope.fnType; - if (fnType) return fnType.retval.getType(); - } - }, - VariableDeclarator: function(parent, node, get) { - if (parent.init == node) return get(parent.id); - } - }; - findTypeFromContext.NewExpression = findTypeFromContext.CallExpression; - - exports.typeFromContext = function(ast, found) { - var parent = exports.parentNode(found.node, ast); - var type = null; - if (findTypeFromContext.hasOwnProperty(parent.type)) { - var finder = findTypeFromContext[parent.type]; - type = finder && finder(parent, found.node, function(node, fromContext) { - var obj = {node: node, state: found.state}; - var tp = fromContext ? exports.typeFromContext(ast, obj) : exports.expressionType(obj); - return tp || ANull; - }); - } - return type || exports.expressionType(found); - }; - - // Flag used to indicate that some wild guessing was used to produce - // a type or set of completions. - var guessing = false; - - exports.resetGuessing = function(val) { guessing = val; }; - exports.didGuess = function() { return guessing; }; - - exports.forAllPropertiesOf = function(type, f) { - type.gatherProperties(f, 0); - }; - - exports.findRefs = function(ast, baseScope, name, refScope, f) { - function handleId(node, scope, ancestors) { - var parent = ancestors[ancestors.length - 2]; - if (parent.type == "MemberExpression" && !parent.computed && !!node.object) return; - if (node.name != name || - (node == ast.id && ast.type == "FunctionDeclaration")) return; - if (parent.property === node) return; - for (var s = scope; s; s = s.prev) { - if (s == refScope) f(node, scope, ancestors); - if (name in s.props) return; - } - } - walk.ancestor(ast, {Identifier: handleId, VariablePattern: handleId}, - exports.fullVisitor, baseScope); - }; - - var simpleWalker = walk.make({ - Function: function(node, _scope, c) { - c(node.body, node.scope, node.expression ? "Expression" : "Statement"); - }, - Statement: function(node, scope, c) { - c(node, node.scope || scope); - } - }); - - exports.findPropRefs = function(ast, scope, objType, name, f) { - // Find the type which owns the property in hierarchy - while (objType && !objType.props[name] && !(objType.maybeProps && objType.maybeProps[name])) { - objType = objType.proto; - } - if (!objType) throw new Error("Couldn't locate property in the base object type."); - - function isObjTypeProto(type) { - // Check whether the found type has objType in its hierarchy - while (type && type != objType) { - // Ff property is overriden higher in the hierarchy, return false - if (type.props[name] || (type.maybeProps && type.maybeProps[name])) { - return false; - } - type = type.proto; - } - return type; - } - - walk.simple(ast, { - MemberExpression: function(node, scope) { - if (node.computed || propName(node) != name) return; - if (isObjTypeProto(findType(node.object, scope).getType())) f(node.property, scope); - }, - ObjectExpression: function(node, scope) { - if (findType(node, scope).getType() != objType) return; - for (var i = 0; i < node.properties.length; ++i) - if (propName(node.properties[i]) == name) f(node.properties[i].key, scope); - }, - MethodDefinition: function(node) { - if (propName(node) != name) return; - if (node.value && isObjTypeProto(getThis(node.value.scope).getType())) f(node.key, node.value.scope); - } - }, simpleWalker, scope); - }; - - // LOCAL-VARIABLE QUERIES - - var scopeAt = exports.scopeAt = function(ast, pos, defaultScope) { - var found = walk.findNodeAround(ast, pos, function(_, node) { - return node.scope; - }); - if (found) return found.node.scope; - else return defaultScope || cx.topScope; - }; - - exports.forAllLocalsAt = function(ast, pos, defaultScope, f) { - var scope = scopeAt(ast, pos, defaultScope); - scope.gatherProperties(f, 0); - }; - - // INIT DEF MODULE - - // Delayed initialization because of cyclic dependencies. - def = exports.def = def.init({}, exports); -}); -// When enabled, this plugin will gather (short) strings in your code, -// and completing when inside a string will try to complete to -// previously seen strings. Takes a single option, maxLength, which -// controls the maximum length of string values to gather, and -// defaults to 15. - -(function(mod) { - if (typeof exports == "object" && typeof module == "object") // CommonJS - return mod(require("../lib/infer"), require("../lib/tern"), require("acorn-walk")); - if (typeof define == "function" && define.amd) // AMD - return define(["../lib/infer", "../lib/tern", "acorn-walk/dist/walk"], mod); - mod(tern, tern, acorn.walk); -})(function(infer, tern, walk) { - "use strict"; - - tern.registerPlugin("complete_strings", function(server, options) { - server.mod.completeStrings = { maxLen: options && options.maxLength || 15, - seen: Object.create(null) }; - server.on("reset", function() { - server.mod.completeStrings.seen = Object.create(null); - }); - server.on("postParse", postParse); - server.on("completion", complete); - }); - - function postParse(ast) { - var data = infer.cx().parent.mod.completeStrings; - walk.simple(ast, { - Literal: function(node) { - if (typeof node.value == "string" && node.value && node.value.length < data.maxLen) - data.seen[node.value] = ast.sourceFile.name; - } - }); - } - - function complete(file, query) { - var pos = tern.resolvePos(file, query.end); - var lit = infer.findExpressionAround(file.ast, null, pos, file.scope, "Literal"); - if (!lit || typeof lit.node.value != "string") return; - var before = lit.node.value.slice(0, pos - lit.node.start - 1); - var matches = [], seen = infer.cx().parent.mod.completeStrings.seen; - for (var str in seen) if (str.length > before.length && str.indexOf(before) == 0) { - if (query.types || query.docs || query.urls || query.origins) { - var rec = {name: JSON.stringify(str), displayName: str}; - matches.push(rec); - if (query.types) rec.type = "string"; - if (query.origins) rec.origin = seen[str]; - } else { - matches.push(JSON.stringify(str)); - } - } - if (matches.length) return { - start: tern.outputPos(query, file, lit.node.start), - end: tern.outputPos(query, file, pos + (file.text.charAt(pos) == file.text.charAt(lit.node.start) ? 1 : 0)), - isProperty: false, - completions: matches - }; - } -}); - diff --git a/_server/CodeMirror/tern.min.js b/_server/CodeMirror/tern.min.js new file mode 100644 index 00000000..2ea380eb --- /dev/null +++ b/_server/CodeMirror/tern.min.js @@ -0,0 +1 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e.tern||(e.tern={})).signal={})}(this,function(e){function t(e,t){var r=this._handlers||(this._handlers=Object.create(null));(r[e]||(r[e]=[])).push(t)}function r(e,t){var r=this._handlers&&this._handlers[e];if(r)for(var n=0;n"!=e&&h(e,t,r)}),!c.length&&2<=l.length&&!1!==s.guess)for(var P in i.cx.props)h(P,i.cx.props[P][0],0);p="memberCompletion"}else T.forAllLocalsAt(e.ast,r,e.scope,h),s.includeKeywords&&(6<=i.options.ecmaVersion?I:k).forEach(function(e){h(e,null,0,function(e){e.isKeyword=!0})}),p="variableCompletion";i.signal(p,e,r,n,h),!1!==s.sort&&c.sort(S);return i.cx.completingProperty=null,{start:F(s,e,r),end:F(s,e,n),isProperty:!!P,isObjectKey:!!f,completions:c}}},properties:{run:function(e,t){var r=t.prefix,n=[];for(var o in e.cx.props)""==o||r&&0!==o.indexOf(r)||n.push(o);!1!==t.sort&&n.sort(S);return{completions:n}}},type:{takesFile:!0,run:function(e,t,r){var n,o,i,s=L(r,t),a=H(e,t,r,s);(n=a[0])||(s=q(r,t),a=H(e,t,r,s),n=a[0]);o=a[1],i=a[2];var p={guess:T.didGuess(),type:T.toString(i,t.depth),name:n&&n.name,exprName:o,doc:i.doc,url:i.url};n&&$(t,n,p);return w(p)}},documentation:{takesFile:!0,run:function(e,t,r){var n=L(r,t),o=V(e,t,r,n),i=o.getType();i||(n=q(r,t),o=V(e,t,r,n),i=o.getType());var s={url:o.url,doc:B(t,o.doc),type:T.toString(o)};i&&$(t,i,s);return w(s)}},definition:{takesFile:!0,run:function(e,t,r){var n=L(r,t),o=V(e,t,r,n);if(T.didGuess())return{};var i=G(o),s={url:o.url,doc:B(t,o.doc),origin:o.origin};if(o.types)for(var a=o.types.length-1;0<=a;--a){var p=o.types[a];$(t,p,s),i=i||G(p)}{var u,f,l,c;i&&i.node?(u=i.node.sourceFile||e.fileMap[i.origin],f=F(t,u,i.node.start),l=F(t,u,i.node.end),s.start=f,s.end=l,s.file=i.origin,c=Math.max(0,i.node.start-50),s.contextOffset=i.node.start-c,s.context=u.text.slice(c,c+50)):i&&(s.file=i.origin,z(e,t,i,s))}return w(s)}},refs:{takesFile:!0,fullFile:!0,run:function(e,t,r){var n=R(r,t,!0);{if(n&&"Identifier"==n.node.type)return W(e,t,r,n);if(n&&"MemberExpression"==n.node.type&&!n.node.computed){var o=n.node.property;return n.node=n.node.object,U(e,t,r,n,o)}if(n&&"ObjectExpression"==n.node.type)for(var i=N(r,t.end),s=0;s=i)return U(e,t,r,n,a)}else if(n&&"MethodDefinition"==n.node.type){o=n.node.key;return U(e,t,r,n,o)}}throw j("Not at a variable or property name.")}},rename:{takesFile:!0,fullFile:!0,run:function(e,t,r){if("string"!=typeof t.newName)throw j(".query.newName should be a string");var n=R(r,t);if(!n||"Identifier"!=n.node.type)throw j("Not at a variable.");var o=W(e,t,r,n,t.newName),i=o.refs;delete o.refs,o.files=e.files.map(function(e){return e.name});for(var s=o.changes=[],a=0;ag(r,t)&&(o.parent=t,o.excluded&&(o.excluded=null)));var i=new s(e,t);r.files.push(i),r.fileMap[e]=i,null!=n?a(i,n,r):r.options.async?(r.startAsyncAction(),r.options.getFile(e,function(e,t){a(i,t||"",r),r.finishAsyncAction(e)})):a(i,r.options.getFile(e)||"",r)}function c(e,t,r){var n=function(){e.off("everythingFetched",n),clearTimeout(o),h(e,t,r)};e.on("everythingFetched",n);var o=setTimeout(n,e.options.fetchTimeout)}function h(r,e,t){if(r.pending)return c(r,e,t);var n=r.fetchError;if(n)return r.fetchError=null,t(n);0Math.abs(i-r))&&(o=i),n=i+e.length}return o}(b,m.text,n),x=null==w?Math.max(0,m.text.lastIndexOf("\n",n)):w;return T.withContext(g.cx,function(){T.purge(d.name,x,x+d.text.length);var e,t,r=d.text;if(!(e=r.match(/(?:"([^"]*)"|([\w$]+))\s*:\s*function\b/))||(t=P.findNodeAround(d.backing.ast,x,"ObjectExpression"))&&t.node.objType&&(y={type:t.node.objType,prop:e[2]||e[1]}),w&&(e=b.match(/^(.*?)\bfunction\b/))){for(var n=e[1].length,o="",i=0;ie.text.length){if(!r)throw j("Position "+t+" is outside of file.");t=e.text.length}return t};function m(e,t,r){var n,o=r-t;if(e.hasAstral)for(i.lastIndex=t;(n=i.exec(e.text))&&n.index=t)return n}}var k="break do instanceof typeof case else new var catch finally return void continue for switch while debugger function this with default if throw delete in try".split(" "),I=k.concat("export class extends const super yield import let static".split(" ")),D=e.addCompletion=function(e,t,r,n,o){for(var i=e.types||e.docs||e.urls||e.origins,s=i||e.depths,a=0;a ")?(a=this.pos,(p=this.parseType(!0)).call&&!d&&(o=p,p=P.ANull,i=a)):p=P.ANull,d?(u=t,f=h,l=p,c=n,function(e,t){for(var r=[],n=0;n$!:]/)||this.error();return r.apply?function(e,t){return o(r(e,t),n)}:o(r,n)},parseTypeInner:function(e,t,r){var n,i,s,o,a;if(this.eat("fn(")||(n=this.eat("fn*(")))return this.parseFnType(e,t,r,n);if(this.eat("[")){for(var p=this.parseType(e),u=p.call;this.eat(", ");){l=l||[p];var f=this.parseType(e);l.push(f),u=u||f.call}return this.eat("]")||this.error(),u?l?(a=l,function(t,r){return new P.Arr(a.map(function(e){return T(e,t,r)}))}):(o=p,function(e,t){return new P.Arr(o(e,t))}):r&&this.base?(P.Arr.call(this.base,l||p),this.base):new P.Arr(l||p)}if(this.eat("{")){var l=[],c=[],u=!1;if(!this.eat("}"))for(;;0){var h,g=this.spec.indexOf(": ",this.pos);-1!=g&&(h=this.spec.slice(this.pos,g),/^[$\w?]+$/.test(h)?this.pos=g+2:h=null);var d=this.parseType(e);if(d.call&&(u=!0),c.push(h),l.push(d),!this.eat(", ")){this.eat("}")||this.error();break}}if(u)return i=c,s=l,function(r,n){var o=new P.Obj;return i.forEach(function(e,t){o.defProp(e).addType(T(s[t],r,n))}),o};var y=new P.Obj;return c.forEach(function(e,t){y.defProp(e).addType(l[t])}),y}if(this.eat("+")){var v=this.word(/[\w$<>\.:!]/),m=P.cx().localDefs[v+".prototype"];if(!m){if(!((m=O(v))instanceof P.Obj))return m;var b=A(m,["prototype"]);(b=b&&b.getObjType())&&(m=b)}return e&&this.eat("[")?this.parsePoly(m):r&&this.base?((t=(this.base.proto=m).hasCtor&&m.hasCtor.name||m.name)&&(this.base.name=t),this.base):r&&this.forceNew?new P.Obj(m):P.getInstance(m)}if(this.eat(":")){t=this.word(/[\w$\.]/);return P.getSymbol(t)}if(e&&this.eat("!")){var w=this.word(/\d/);if(w)return w=Number(w),function(e,t){return t[w]||P.ANull};if(this.eat("this"))return function(e){return e};if(this.eat("custom:")){var x=this.word(/[\w$]/);return E[x]||function(){return P.ANull}}return this.fromWord("!"+this.word(/[\w$<>\.!:]/))}return this.eat("?")?P.ANull:this.fromWord(this.word(/[\w$<>\.!:`]/))},fromWord:function(e){var t=P.cx();switch(e){case"number":return t.num;case"string":return t.str;case"bool":return t.bool;case"":return t.topScope}return t.localDefs&&e in t.localDefs?t.localDefs[e]:O(e)},parsePoly:function(n){var e,o="";(e=this.spec.slice(this.pos).match(/^\s*([\w$:]+)\s*=\s*/))&&(o=e[1],this.pos+=e[0].length);var i=this.parseType(!0);if(this.eat("]")||this.error(),i.call)return function(e,t){var r=new P.Obj(n);return i(e,t).propagate(r.defProp(o)),r};var t=new P.Obj(n);return i.propagate(t.defProp(o)),t}};var p,d=e.parseEffect=function(e,t){var r;if(0==e.indexOf("propagate ")){var n=(s=new h(e,10)).parseType(!0);s.eat(" ")||s.error();var o=s.parseType(!0);g(t,function(e,t){T(n,e,t).propagate(T(o,e,t))})}else if(0==e.indexOf("call ")){var a=5==e.indexOf("and return ",5),p=(s=new h(e,a?16:5)).parseType(!0),u=null,f=[];for(s.eat(" this=")&&(u=s.parseType(!0));s.eat(" ");)f.push(s.parseType(!0));g(t,function(e,t){for(var r=T(p,e,t),n=u?T(u,e,t):P.ANull,o=[],i=0;i"!=e&&n.propagate(new P.DefProp(e,t))})})}},O=e.parsePath=function(e,t){var r=P.cx(),n=r.paths[e],o=e;if(null!=n)return n;r.paths[e]=P.ANull;var i=t||p||r.topScope;if(r.localDefs)for(var s in r.localDefs)if(0==e.indexOf(s)){if(e==s)return r.paths[e]=r.localDefs[e];if("."==e.charAt(s.length)){i=r.localDefs[s],e=e.slice(s.length+1);break}}var a=A(i,e.split("."));return r.paths[o]=a==P.ANull?null:a,a};function A(e,t){for(var r=0;r"),o=0;o").getType(!1);if(!a)return r;var p=r.getProp("").getType(!1);return!p||c(a,p,n+1)?r:void 0}d.prototype=t(g,{addType:function(r,n){if(n=n||100,this.maxWeightn||-1"!=t){var o=e.hasProp("");if(o)return o.getType()}else if(e.props[""]!=this)for(var i in e.props){var s=e.props[i];if(!s.isEmpty())return s.getType()}},makeupType:function(){var e=this.propertyOf&&this.makeupPropType(this.propertyOf);if(e)return e;if(!this.forward)return null;for(var t=this.forward.length-1;0<=t;--t){var r=this.forward[t].typeHint();if(r&&!r.isEmpty())return ke=!0,r}for(var n=Object.create(null),o=null,t=0;t"!=p&&"✖"!=p&&p!=H.completingProperty&&(n[p]=!0,o=p)}if(!o)return null;var i=_(o);if(i){var s=[];e:for(t=0;t").isEmpty()?1:2;else if(r){u=1;for(var f=0;f"==this.prop||!/[^\w_]/.test(this.prop))return{target:this.target,pathExt:"."+this.prop}}}),v=u.PropHasSubset=u.DefProp=r({construct:function(e,t,r){this.prop=e,this.type=t,this.originNode=r},addType:function(e,t){var r;e instanceof I&&((r=e.defProp(this.prop,this.originNode)).origin||(r.origin=this.origin),this.type.propagate(r,t))},propHint:function(){return this.prop}}),m=r({construct:function(e){this.c=e},addType:function(e){e instanceof I&&e.forAllProps(this.c)}});var b=u.IsCallee=r({construct:function(e,t,r,n){this.self=e,this.args=t,this.argNodes=r,this.retval=n,this.disabled=H.disabledComputing},addType:function(e,t){if(e instanceof L){for(var r=0;r"!=n){if(5"},broadcastProp:function(e,t,r){var n,o;if(r&&(this.signal("addProp",e,t),this instanceof W||(n=e,o=this,(H.props[n]||(H.props[n]=[])).push(o))),this.onNewProp)for(var i=0;i"!=r&&":"!=r.charAt(0)&&e(r,this,t);this.proto&&this.proto.gatherProperties(e,t+1)},getObjType:function(){return this}});var D="undefined"!=typeof StopIteration;function M(e){return"__proto__"==e||"✖"==e||D&&"__iterator__"==e}var L=u.Fn=function(e,t,r,n,o,i,s){I.call(this,H.protos.Function,e),this.self=t,this.args=r,this.argNames=n,this.retval=o,this.generator=i,this.async=s};L.prototype=t(I.prototype,{constructor:L,toString:function(e){null==e&&(e=0);for(var t=this.generator?"fn*(":"fn(",r=0;r");if(Array.isArray(e)){this.tuple=e.length;for(var r=0;r"),e-1,this);return"["+t+"]"},normalizeIntegerProp:function(e){return+e"}});var R=u.Sym=function(e,t){C.call(this,H.protos.Symbol,"Symbol"),this.symName=e,this.originNode=t};function _(e){return H.props[e]}R.prototype=t(C.prototype,{constructor:R,asPropName:function(){return":"+this.symName},getSymbolType:function(){return this}}),u.getSymbol=function(e,t){var r=e.replace(/[^\w$\.]/g,"_"),n=H.symbols[r];return n?(t&&!n.originNode&&(n.originNode=t),n):H.symbols[r]=new R(r,t)},u.Context=function(t,e){this.parent=e,this.props=Object.create(null),this.protos=Object.create(null),this.origins=[],this.curOrigin="ecmascript",this.paths=Object.create(null),this.definitions=Object.create(null),this.purgeGen=0,this.workList=null,this.disabledComputing=null,this.curSuperCtor=this.curSuper=null,this.symbols=Object.create(null),u.withContext(this,function(){if(H.protos.Object=new I(null,"Object.prototype"),H.topScope=new W,H.topScope.name="",H.protos.Array=new I(!0,"Array.prototype"),H.protos.Function=new L("Function.prototype",g,[],[],g),H.protos.Function.proto=H.protos.Object,H.protos.RegExp=new I(!0,"RegExp.prototype"),H.protos.String=new I(!0,"String.prototype"),H.protos.Number=new I(!0,"Number.prototype"),H.protos.Boolean=new I(!0,"Boolean.prototype"),H.protos.Symbol=new I(!0,"Symbol.prototype"),H.str=new C(H.protos.String,"string"),H.bool=new C(H.protos.Boolean,"bool"),H.num=new C(H.protos.Number,"number"),H.curOrigin=null,t)for(var e=0;e=V)throw new u.TimedOut;o=n[r+3]+1,n[r+1].addType(n[r],n[r+2])}return H.workList=null,t}function z(e,t,r){var n=H.curSuperCtor,o=H.curSuper;H.curSuperCtor=e,H.curSuper=t;var i=r();return H.curSuperCtor=n,H.curSuper=o,i}var W=u.Scope=function(e,t,r,n){I.call(this,e||!0),this.prev=e,this.originNode=t,this.isBlock=!!r,this.isCatch=!!n};function U(e,t){for(;e.isBlock||e.isCatch||!1===t&&e.fnType&&e.fnType.isArrowFn();)e=e.prev;return e}function K(e,t){var r=U(e).fnType;r&&(r.instantiateScore=(r.instantiateScore||0)+t)}W.prototype=t(I.prototype,{constructor:W,defVar:function(e,t){for(var r=this;;r=r.proto){var n=r.props[e];if(n)return n;if(!r.prev)return r.defProp(e,t)}}});var Z={};function J(e,t){var r=t.instantiateScore;if(!H.disabledComputing&&r&&t.args.length&&function(e,t){try{return h.simple(e,{Expression:function(){if(--t<=0)throw Z}}),1}catch(e){if(e==Z)return;throw e}}(e,5*r))return K(U(t.originNode.scope.prev),r/2),function(f,l){for(var c=f.scope,e=0;e"));for(var n=u(e.self,"!this",0),o=0;!n&&o"};function se(e){var t=e.getSymbolType();if(t)return t.asPropName()}function ae(e){switch(e){case"+":case"-":case"~":return H.num;case"!":return H.bool;case"typeof":return H.str;case"void":case"delete":return g}}function pe(e){switch(e){case"==":case"!=":case"===":case"!==":case"<":case">":case">=":case"<=":case"in":case"instanceof":return 1}}function ue(e){if(e.regex)return P(H.protos.RegExp);switch(typeof e.value){case"boolean":return H.bool;case"number":return H.num;case"string":return H.str;case"object":case"function":return e.value?P(H.protos.RegExp):g}}function fe(e,t){for(var r=0;r"==(s=ie(p,f))||"set"==p.kind?i=g:((i=(p.static?n:c).defProp(s,p.key)).initializer=!0,"get"==p.kind&&(i=new b(o,[],null,i))),we(p.value,f,i),(a=i.getFunctionType())&&a.self.addType(o))}return n})}function ye(e,t,r){var n=1"==(t=ie(o,a))||"set"==o.kind?r=g:((n=r=u.defProp(t,i)).initializer=!0,"get"==o.kind&&(r=new b(u,[],null,n))),we(o.value,a,r,t),"FunctionExpression"==o.value.type&&o.value.scope.fnType.self.addType(u,2))}}),u}),FunctionExpression:ve(function(e,t,r){var n=e.scope,o=n.fnType;return r&&!o.name&&(o.name=r),fe(e,n),e.expression?we(e.body,n,n.fnType.retval=new d):h.recursive(e.body,n,null,Pe,"Statement"),"ArrowFunctionExpression"==e.type&&ge(t).propagate(o.self),J(e,o)||Q(o),e.id&&n.getProp(e.id.name).addType(o),o}),ClassExpression:ve(de),SequenceExpression:ve(function(e,t){for(var r=0,n=e.expressions.length-1;r"==o){var s=e.left.property.name,a=t.props[s],p=a&&a.iteratesOver;if(p){K(t,20);var u="MemberExpression"==e.right.type&&e.right.computed&&e.right.property.name==s;return p.forAllProps(function(e,t,r){r&&"prototype"!=e&&""!=e&&i.propagate(new v(e,u?t:g))}),n}}i.propagate(new v(o,n,e.left.property)),function e(t){t.isEmpty()&&t.propertyOf&&(t.propertyOf.getProp(t.propertyName).addType(new I,f),e(t.propertyOf))}(i),"FunctionExpression"==e.right.type&&i.propagate(e.right.scope.fnType.self,2)}else he(e.left,t,n);return n}),LogicalExpression:me(function(e,t,r){we(e.left,t,r),we(e.right,t,r)}),ConditionalExpression:me(function(e,t,r){we(e.test,t,g),we(e.consequent,t,r),we(e.alternate,t,r)}),NewExpression:me(function(e,t,r,n){"Identifier"==e.callee.type&&e.callee.name in t.props&&K(t,20);for(var o=0,i=[];o"==s&&((i=se(o=we(e.property,t)))?s=e.propName=i:o.hasType(H.num)||(n=6)),we(e.object,t).getProp(s).propagate(r,n)}),Identifier:ve(function(e,t){var r;return"arguments"==e.name&&(!(r=U(t,!1)).fnType||e.name in r.props||r.defProp(e.name,r.fnType.originNode).addType(new q(r.fnType.arguments=new d))),t.getProp(e.name)}),ThisExpression:ve(function(e,t){return ge(t)}),Super:ve(function(e){return e.superType=H.curSuper||g}),Literal:ve(ue),TemplateLiteral:ve(function(e,t){for(var r=0;r").propagate(le(n,t))):he(n,t,o.getProp(""))),r(e.body,t,"Statement")},ForOfStatement:function(e,t,r){var n,o=xe(e.left);"Identifier"==o.type?n=le(o,t):he(o,t,n=new d),e.await?we(e.right,t,new w(":Symbol.asyncIterator",[],null,new w("next",[],null,new p(":t",new p("value",n))))):we(e.right,t,new w(":Symbol.iterator",[],null,new w("next",[],null,new p("value",n)))),r(e.body,t,"Statement")}}),Te=u.parse=function(t,r,e){var n;r&&!Array.isArray(r)||(r=e);try{n=o.parse(t,r)}catch(e){n=i.parse(t,r)}return n};function Oe(e,t,r){var n=H.definitions.ecmascript,o=new I(!0);o.defProp("done").addType(H.bool),t.propagate(o.defProp("value"));var i=o;r&&n&&(i=new I(n["Promise.prototype"])).getType().propagate(new v(":t",o));var s=new L(null,g,e?[e]:[],e?["?"]:[],i),a=new I(!n||(r?n.async_generator_prototype:n.generator_prototype));return a.defProp("next").addType(s),a}function Ae(e,t){return e.generator?e.computeRet?Oe(e.yieldval,t,e.async):(!0===e.generator&&(e.generator=Oe(e.yieldval,t,e.async)),e.generator):t}function Ee(e,t,r){var n=Ne(e,r).getFunctionType();if(!n)return g;var o=n.retval;if(n.computeRet){for(var i=0,s=[];i=n&&t.end<=o&&-1=n&&t.end<=o&&e.origin==r}}(e,t,r);for(var o in++H.purgeGen,H.topScope.purge(n),H.props){for(var i=H.props[o],s=0;s"==r?g:function(e){ke=!0;var t=_(e);if(t)for(var r=0;rr)&&(("Identifier"!=t.type||"✖"!=t.name)&&je.hasOwnProperty(t.type))};return h.findNodeAround(e,t,i,Se,n||H.topScope)},u.findExpressionAround=function(e,r,t,n,o){var i=o||function(e,t){return!(null!=r&&t.start>r)&&(("Identifier"!=t.type||"✖"!=t.name)&&je.hasOwnProperty(t.type))};return h.findNodeAround(e,t,i,Fe,n||H.topScope)},u.expressionType=function(e){return Ne(e.node,e.state)},u.parentNode=function(i,e){var s=[];try{!function e(t,r,n){if(t.start<=i.start&&t.end>=i.end){var o=s[s.length-1];if(t==i)throw{found:o};o!=t&&s.push(t),h.base[n||t.type](t,r,e),o!=t&&s.pop()}}(e,null)}catch(e){if(e.found)return e.found;throw e}};var Ce=u.findTypeFromContext={ArrayExpression:function(e,t,r){return r(e,!0).getProp("")},ObjectExpression:function(e,t,r){for(var n=0;ni.length&&0==p.indexOf(i)&&(t.types||t.docs||t.urls||t.origins?(o={name:JSON.stringify(p),displayName:p},s.push(o),t.types&&(o.type="string"),t.origins&&(o.origin=a[p])):s.push(JSON.stringify(p)))}return s.length?{start:f.outputPos(t,e,n.node.start),end:f.outputPos(t,e,r+(e.text.charAt(r)==e.text.charAt(n.node.start)?1:0)),isProperty:!1,completions:s}:void 0}}f.registerPlugin("complete_strings",function(e,t){e.mod.completeStrings={maxLen:t&&t.maxLength||15,seen:Object.create(null)},e.on("reset",function(){e.mod.completeStrings.seen=Object.create(null)}),e.on("postParse",r),e.on("completion",n)})}); \ No newline at end of file diff --git a/editor-mobile.html b/editor-mobile.html index 17a5acea..8af896bf 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -470,10 +470,10 @@ - + - + diff --git a/editor.html b/editor.html index 50afcd74..8c88732b 100644 --- a/editor.html +++ b/editor.html @@ -453,10 +453,10 @@ - + - +