Bug 1591404 - Remove unused tern and show-hint CodeMirror addons. r=gl.

Differential Revision: https://phabricator.services.mozilla.com/D50937

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Nicolas Chevobbe 2019-10-30 06:58:51 +00:00
parent 09a1cf803b
commit 6043a21348
26 changed files with 2 additions and 9641 deletions

View file

@ -67,7 +67,6 @@ xpcom/reflect/xptcall/md/unix/.*
browser/components/translation/cld2/.*
browser/extensions/mortar/ppapi/.*
devtools/client/shared/sourceeditor/codemirror/.*
devtools/client/shared/sourceeditor/tern/.*
dom/canvas/test/webgl-conf/checkout/closure-library/.*
dom/media/gmp/rlz/.*
dom/media/gmp/widevine-adapter/content_decryption_module.h

View file

@ -118,7 +118,6 @@ devtools/client/shared/source-map/
devtools/client/shared/vendor/
devtools/client/shared/sourceeditor/codemirror/*.js
devtools/client/shared/sourceeditor/codemirror/**/*.js
devtools/client/shared/sourceeditor/tern/
devtools/client/shared/sourceeditor/test/cm_mode_ruby.js
devtools/client/shared/sourceeditor/test/codemirror/
devtools/server/actors/utils/automation-timeline.js

View file

@ -122,10 +122,6 @@ declare module 'codemirror/addon/hint/javascript-hint' {
declare module.exports: any;
}
declare module 'codemirror/addon/hint/show-hint' {
declare module.exports: any;
}
declare module 'codemirror/addon/hint/sql-hint' {
declare module.exports: any;
}
@ -246,14 +242,6 @@ declare module 'codemirror/addon/selection/selection-pointer' {
declare module.exports: any;
}
declare module 'codemirror/addon/tern/tern' {
declare module.exports: any;
}
declare module 'codemirror/addon/tern/worker' {
declare module.exports: any;
}
declare module 'codemirror/addon/wrap/hardwrap' {
declare module.exports: any;
}
@ -1090,9 +1078,6 @@ declare module 'codemirror/addon/hint/html-hint.js' {
declare module 'codemirror/addon/hint/javascript-hint.js' {
declare module.exports: $Exports<'codemirror/addon/hint/javascript-hint'>;
}
declare module 'codemirror/addon/hint/show-hint.js' {
declare module.exports: $Exports<'codemirror/addon/hint/show-hint'>;
}
declare module 'codemirror/addon/hint/sql-hint.js' {
declare module.exports: $Exports<'codemirror/addon/hint/sql-hint'>;
}
@ -1183,12 +1168,6 @@ declare module 'codemirror/addon/selection/mark-selection.js' {
declare module 'codemirror/addon/selection/selection-pointer.js' {
declare module.exports: $Exports<'codemirror/addon/selection/selection-pointer'>;
}
declare module 'codemirror/addon/tern/tern.js' {
declare module.exports: $Exports<'codemirror/addon/tern/tern'>;
}
declare module 'codemirror/addon/tern/worker.js' {
declare module.exports: $Exports<'codemirror/addon/tern/worker'>;
}
declare module 'codemirror/addon/wrap/hardwrap.js' {
declare module.exports: $Exports<'codemirror/addon/wrap/hardwrap'>;
}

View file

@ -14,8 +14,6 @@ devtools.jar:
content/storage/index.xul (storage/index.xul)
content/inspector/markup/markup.xhtml (inspector/markup/markup.xhtml)
content/shared/sourceeditor/codemirror/addon/dialog/dialog.css (shared/sourceeditor/codemirror/addon/dialog/dialog.css)
content/shared/sourceeditor/codemirror/addon/hint/show-hint.js (shared/sourceeditor/codemirror/addon/hint/show-hint.js)
content/shared/sourceeditor/codemirror/addon/tern/tern.js (shared/sourceeditor/codemirror/addon/tern/tern.js)
content/shared/sourceeditor/codemirror/keymap/emacs.js (shared/sourceeditor/codemirror/keymap/emacs.js)
content/shared/sourceeditor/codemirror/keymap/vim.js (shared/sourceeditor/codemirror/keymap/vim.js)
content/shared/sourceeditor/codemirror/keymap/sublime.js (shared/sourceeditor/codemirror/keymap/sublime.js)

View file

@ -18,11 +18,6 @@ loader.lazyRequireGetter(
"devtools/client/shared/sourceeditor/css-autocompleter"
);
const CM_TERN_SCRIPTS = [
"chrome://devtools/content/shared/sourceeditor/codemirror/addon/tern/tern.js",
"chrome://devtools/content/shared/sourceeditor/codemirror/addon/hint/show-hint.js",
];
const autocompleteMap = new WeakMap();
/**
@ -35,83 +30,12 @@ function initializeAutoCompletion(ctx, options = {}) {
}
const win = ed.container.contentWindow.wrappedJSObject;
const { CodeMirror, document } = win;
const { CodeMirror } = win;
let completer = null;
const autocompleteKey =
"Ctrl-" + Editor.keyFor("autocompletion", { noaccel: true });
if (ed.config.mode == Editor.modes.js) {
const defs = [require("./tern/browser"), require("./tern/ecma5")];
CM_TERN_SCRIPTS.forEach(ed.loadScript, ed);
win.tern = require("./tern/tern");
cm.tern = new CodeMirror.TernServer({
defs: defs,
typeTip: function(data) {
const tip = document.createElement("span");
tip.className = "CodeMirror-Tern-information";
const tipType = document.createElement("strong");
const tipText = document.createTextNode(
data.type || cm.l10n("autocompletion.notFound")
);
tipType.appendChild(tipText);
tip.appendChild(tipType);
if (data.doc) {
tip.appendChild(document.createTextNode(" — " + data.doc));
}
if (data.url) {
tip.appendChild(document.createTextNode(" "));
const docLink = document.createElement("a");
docLink.textContent = "[" + cm.l10n("autocompletion.docsLink") + "]";
docLink.href = data.url;
docLink.className = "theme-link";
docLink.setAttribute("target", "_blank");
tip.appendChild(docLink);
}
return tip;
},
});
const keyMap = {};
const updateArgHintsCallback = cm.tern.updateArgHints.bind(cm.tern, cm);
cm.on("cursorActivity", updateArgHintsCallback);
keyMap[autocompleteKey] = cmArg => {
cmArg.tern.getHint(cmArg, data => {
CodeMirror.on(data, "shown", () => ed.emit("before-suggest"));
CodeMirror.on(data, "close", () => ed.emit("after-suggest"));
CodeMirror.on(data, "select", () => ed.emit("suggestion-entered"));
CodeMirror.showHint(cmArg, (cmIgnore, cb) => cb(data), { async: true });
});
};
keyMap[Editor.keyFor("showInformation2", { noaccel: true })] = cmArg => {
cmArg.tern.showType(cmArg, null, () => {
ed.emit("show-information");
});
};
cm.addKeyMap(keyMap);
const destroyTern = function() {
ed.off("destroy", destroyTern);
cm.off("cursorActivity", updateArgHintsCallback);
cm.removeKeyMap(keyMap);
win.tern = cm.tern = null;
autocompleteMap.delete(ed);
};
ed.on("destroy", destroyTern);
autocompleteMap.set(ed, {
destroy: destroyTern,
});
// TODO: Integrate tern autocompletion with this autocomplete API.
return;
} else if (ed.config.mode == Editor.modes.css) {
if (ed.config.mode == Editor.modes.css) {
completer = new CSSCompleter({
walker: options.walker,
cssProperties: options.cssProperties,

View file

@ -1,460 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var HINT_ELEMENT_CLASS = "CodeMirror-hint";
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";
// This is the old interface, kept around for now to stay
// backwards-compatible.
CodeMirror.showHint = function(cm, getHints, options) {
if (!getHints) return cm.showHint(options);
if (options && options.async) getHints.async = true;
var newOpts = {hint: getHints};
if (options) for (var prop in options) newOpts[prop] = options[prop];
return cm.showHint(newOpts);
};
CodeMirror.defineExtension("showHint", function(options) {
options = parseOptions(this, this.getCursor("start"), options);
var selections = this.listSelections()
if (selections.length > 1) return;
// By default, don't allow completion when something is selected.
// A hint function can have a `supportsSelection` property to
// indicate that it can handle selections.
if (this.somethingSelected()) {
if (!options.hint.supportsSelection) return;
// Don't try with cross-line selections
for (var i = 0; i < selections.length; i++)
if (selections[i].head.line != selections[i].anchor.line) return;
}
if (this.state.completionActive) this.state.completionActive.close();
var completion = this.state.completionActive = new Completion(this, options);
if (!completion.options.hint) return;
CodeMirror.signal(this, "startCompletion", this);
completion.update(true);
});
CodeMirror.defineExtension("closeHint", function() {
if (this.state.completionActive) this.state.completionActive.close()
})
function Completion(cm, options) {
this.cm = cm;
this.options = options;
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 self = this;
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); });
}
var requestAnimationFrame = window.requestAnimationFrame || function(fn) {
return setTimeout(fn, 1000/60);
};
var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;
Completion.prototype = {
close: function() {
if (!this.active()) return;
this.cm.state.completionActive = null;
this.tick = null;
this.cm.off("cursorActivity", this.activityFunc);
if (this.widget && this.data) CodeMirror.signal(this.data, "close");
if (this.widget) this.widget.close();
CodeMirror.signal(this.cm, "endCompletion", this.cm);
},
active: function() {
return this.cm.state.completionActive == this;
},
pick: function(data, i) {
var completion = data.list[i];
if (completion.hint) completion.hint(this.cm, data, completion);
else this.cm.replaceRange(getText(completion), completion.from || data.from,
completion.to || data.to, "complete");
CodeMirror.signal(data, "pick", completion);
this.close();
},
cursorActivity: function() {
if (this.debounce) {
cancelAnimationFrame(this.debounce);
this.debounce = 0;
}
var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
(!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
this.close();
} else {
var self = this;
this.debounce = requestAnimationFrame(function() {self.update();});
if (this.widget) this.widget.disable();
}
},
update: function(first) {
if (this.tick == null) return
var self = this, myTick = ++this.tick
fetchHints(this.options.hint, this.cm, this.options, function(data) {
if (self.tick == myTick) self.finishUpdate(data, first)
})
},
finishUpdate: function(data, first) {
if (this.data) CodeMirror.signal(this.data, "update");
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
if (this.widget) this.widget.close();
this.data = data;
if (data && data.list.length) {
if (picked && data.list.length == 1) {
this.pick(data, 0);
} else {
this.widget = new Widget(this, data);
CodeMirror.signal(data, "shown");
}
}
}
};
function parseOptions(cm, pos, options) {
var editor = cm.options.hintOptions;
var out = {};
for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
if (editor) for (var prop in editor)
if (editor[prop] !== undefined) out[prop] = editor[prop];
if (options) for (var prop in options)
if (options[prop] !== undefined) out[prop] = options[prop];
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
return out;
}
function getText(completion) {
if (typeof completion == "string") return completion;
else return completion.text;
}
function buildKeyMap(completion, handle) {
var baseMap = {
Up: function() {handle.moveFocus(-1);},
Down: function() {handle.moveFocus(1);},
PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);},
PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);},
Home: function() {handle.setFocus(0);},
End: function() {handle.setFocus(handle.length - 1);},
Enter: handle.pick,
Tab: handle.pick,
Esc: handle.close
};
var mac = /Mac/.test(navigator.platform);
if (mac) {
baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);};
baseMap["Ctrl-N"] = function() {handle.moveFocus(1);};
}
var custom = completion.options.customKeys;
var ourMap = custom ? {} : baseMap;
function addBinding(key, val) {
var bound;
if (typeof val != "string")
bound = function(cm) { return val(cm, handle); };
// This mechanism is deprecated
else if (baseMap.hasOwnProperty(val))
bound = baseMap[val];
else
bound = val;
ourMap[key] = bound;
}
if (custom)
for (var key in custom) if (custom.hasOwnProperty(key))
addBinding(key, custom[key]);
var extra = completion.options.extraKeys;
if (extra)
for (var key in extra) if (extra.hasOwnProperty(key))
addBinding(key, extra[key]);
return ourMap;
}
function getHintElement(hintsElement, el) {
while (el && el != hintsElement) {
if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
el = el.parentNode;
}
}
function Widget(completion, data) {
this.completion = completion;
this.data = data;
this.picked = false;
var widget = this, cm = completion.cm;
var ownerDocument = cm.getInputField().ownerDocument;
var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow;
var hints = this.hints = ownerDocument.createElement("ul");
var theme = completion.cm.options.theme;
hints.className = "CodeMirror-hints " + theme;
this.selectedHint = data.selectedHint || 0;
var completions = data.list;
for (var i = 0; i < completions.length; ++i) {
var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i];
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
if (cur.className != null) className = cur.className + " " + className;
elt.className = className;
if (cur.render) cur.render(elt, data, cur);
else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur)));
elt.hintId = i;
}
var container = completion.options.container || ownerDocument.body;
var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
var left = pos.left, top = pos.bottom, below = true;
var offsetLeft = 0, offsetTop = 0;
if (container !== ownerDocument.body) {
// We offset the cursor position because left and top are relative to the offsetParent's top left corner.
var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1;
var offsetParent = isContainerPositioned ? container : container.offsetParent;
var offsetParentPosition = offsetParent.getBoundingClientRect();
var bodyPosition = ownerDocument.body.getBoundingClientRect();
offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft);
offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop);
}
hints.style.left = (left - offsetLeft) + "px";
hints.style.top = (top - offsetTop) + "px";
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth);
var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight);
container.appendChild(hints);
var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
var scrolls = hints.scrollHeight > hints.clientHeight + 1
var startScroll = cm.getScrollInfo();
if (overlapY > 0) {
var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
if (curTop - height > 0) { // Fits above cursor
hints.style.top = (top = pos.top - height - offsetTop) + "px";
below = false;
} else if (height > winH) {
hints.style.height = (winH - 5) + "px";
hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px";
var cursor = cm.getCursor();
if (data.from.ch != cursor.ch) {
pos = cm.cursorCoords(cursor);
hints.style.left = (left = pos.left - offsetLeft) + "px";
box = hints.getBoundingClientRect();
}
}
}
var overlapX = box.right - winW;
if (overlapX > 0) {
if (box.right - box.left > winW) {
hints.style.width = (winW - 5) + "px";
overlapX -= (box.right - box.left) - winW;
}
hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px";
}
if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling)
node.style.paddingRight = cm.display.nativeBarWidth + "px"
cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
setFocus: function(n) { widget.changeActive(n); },
menuSize: function() { return widget.screenAmount(); },
length: completions.length,
close: function() { completion.close(); },
pick: function() { widget.pick(); },
data: data
}));
if (completion.options.closeOnUnfocus) {
var closingOnBlur;
cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); });
cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); });
}
cm.on("scroll", this.onScroll = function() {
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
var newTop = top + startScroll.top - curScroll.top;
var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop);
if (!below) point += hints.offsetHeight;
if (point <= editor.top || point >= editor.bottom) return completion.close();
hints.style.top = newTop + "px";
hints.style.left = (left + startScroll.left - curScroll.left) + "px";
});
CodeMirror.on(hints, "dblclick", function(e) {
var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();}
});
CodeMirror.on(hints, "click", function(e) {
var t = getHintElement(hints, e.target || e.srcElement);
if (t && t.hintId != null) {
widget.changeActive(t.hintId);
if (completion.options.completeOnSingleClick) widget.pick();
}
});
CodeMirror.on(hints, "mousedown", function() {
setTimeout(function(){cm.focus();}, 20);
});
CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]);
return true;
}
Widget.prototype = {
close: function() {
if (this.completion.widget != this) return;
this.completion.widget = null;
this.hints.parentNode.removeChild(this.hints);
this.completion.cm.removeKeyMap(this.keyMap);
var cm = this.completion.cm;
if (this.completion.options.closeOnUnfocus) {
cm.off("blur", this.onBlur);
cm.off("focus", this.onFocus);
}
cm.off("scroll", this.onScroll);
},
disable: function() {
this.completion.cm.removeKeyMap(this.keyMap);
var widget = this;
this.keyMap = {Enter: function() { widget.picked = true; }};
this.completion.cm.addKeyMap(this.keyMap);
},
pick: function() {
this.completion.pick(this.data, this.selectedHint);
},
changeActive: function(i, avoidWrap) {
if (i >= this.data.list.length)
i = avoidWrap ? this.data.list.length - 1 : 0;
else if (i < 0)
i = avoidWrap ? 0 : this.data.list.length - 1;
if (this.selectedHint == i) return;
var node = this.hints.childNodes[this.selectedHint];
if (node) node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
node = this.hints.childNodes[this.selectedHint = i];
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
if (node.offsetTop < this.hints.scrollTop)
this.hints.scrollTop = node.offsetTop - 3;
else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
},
screenAmount: function() {
return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
}
};
function applicableHelpers(cm, helpers) {
if (!cm.somethingSelected()) return helpers
var result = []
for (var i = 0; i < helpers.length; i++)
if (helpers[i].supportsSelection) result.push(helpers[i])
return result
}
function fetchHints(hint, cm, options, callback) {
if (hint.async) {
hint(cm, callback, options)
} else {
var result = hint(cm, options)
if (result && result.then) result.then(callback)
else callback(result)
}
}
function resolveAutoHints(cm, pos) {
var helpers = cm.getHelpers(pos, "hint"), words
if (helpers.length) {
var resolved = function(cm, callback, options) {
var app = applicableHelpers(cm, helpers);
function run(i) {
if (i == app.length) return callback(null)
fetchHints(app[i], cm, options, function(result) {
if (result && result.list.length > 0) callback(result)
else run(i + 1)
})
}
run(0)
}
resolved.async = true
resolved.supportsSelection = true
return resolved
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) }
} else if (CodeMirror.hint.anyword) {
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) }
} else {
return function() {}
}
}
CodeMirror.registerHelper("hint", "auto", {
resolve: resolveAutoHints
});
CodeMirror.registerHelper("hint", "fromList", function(cm, options) {
var cur = cm.getCursor(), token = cm.getTokenAt(cur)
var term, from = CodeMirror.Pos(cur.line, token.start), to = cur
if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) {
term = token.string.substr(0, cur.ch - token.start)
} else {
term = ""
from = cur
}
var found = [];
for (var i = 0; i < options.words.length; i++) {
var word = options.words[i];
if (word.slice(0, term.length) == term)
found.push(word);
}
if (found.length) return {list: found, from: from, to: to};
});
CodeMirror.commands.autocomplete = CodeMirror.showHint;
var defaultOptions = {
hint: CodeMirror.hint.auto,
completeSingle: true,
alignWithWord: true,
closeCharacters: /[\s()\[\]{};:>,]/,
closeOnUnfocus: true,
completeOnSingleClick: true,
container: null,
customKeys: null,
extraKeys: null
};
CodeMirror.defineOption("hintOptions", null);
});

View file

@ -1,87 +0,0 @@
.CodeMirror-Tern-completion {
padding-left: 22px;
position: relative;
line-height: 1.5;
}
.CodeMirror-Tern-completion:before {
position: absolute;
left: 2px;
bottom: 2px;
border-radius: 50%;
font-size: 12px;
font-weight: bold;
height: 15px;
width: 15px;
line-height: 16px;
text-align: center;
color: white;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.CodeMirror-Tern-completion-unknown:before {
content: "?";
background: #4bb;
}
.CodeMirror-Tern-completion-object:before {
content: "O";
background: #77c;
}
.CodeMirror-Tern-completion-fn:before {
content: "F";
background: #7c7;
}
.CodeMirror-Tern-completion-array:before {
content: "A";
background: #c66;
}
.CodeMirror-Tern-completion-number:before {
content: "1";
background: #999;
}
.CodeMirror-Tern-completion-string:before {
content: "S";
background: #999;
}
.CodeMirror-Tern-completion-bool:before {
content: "B";
background: #999;
}
.CodeMirror-Tern-completion-guess {
color: #999;
}
.CodeMirror-Tern-tooltip {
border: 1px solid silver;
border-radius: 3px;
color: #444;
padding: 2px 5px;
font-size: 90%;
font-family: monospace;
background-color: white;
white-space: pre-wrap;
max-width: 40em;
position: absolute;
z-index: 10;
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2);
box-shadow: 2px 3px 5px rgba(0,0,0,.2);
transition: opacity 1s;
-moz-transition: opacity 1s;
-webkit-transition: opacity 1s;
-o-transition: opacity 1s;
-ms-transition: opacity 1s;
}
.CodeMirror-Tern-hint-doc {
max-width: 25em;
margin-top: -3px;
}
.CodeMirror-Tern-fname { color: black; }
.CodeMirror-Tern-farg { color: #70a; }
.CodeMirror-Tern-farg-current { text-decoration: underline; }
.CodeMirror-Tern-type { color: #07c; }
.CodeMirror-Tern-fhint-guess { opacity: .7; }

View file

@ -1,718 +0,0 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
// Glue code between CodeMirror and Tern.
//
// Create a CodeMirror.TernServer to wrap an actual Tern server,
// register open documents (CodeMirror.Doc instances) with it, and
// call its methods to activate the assisting functions that Tern
// provides.
//
// Options supported (all optional):
// * defs: An array of JSON definition data structures.
// * plugins: An object mapping plugin names to configuration
// options.
// * getFile: A function(name, c) that can be used to access files in
// the project that haven't been loaded yet. Simply do c(null) to
// indicate that a file is not available.
// * fileFilter: A function(value, docName, doc) that will be applied
// to documents before passing them on to Tern.
// * switchToDoc: A function(name, doc) that should, when providing a
// multi-file view, switch the view or focus to the named file.
// * showError: A function(editor, message) that can be used to
// override the way errors are displayed.
// * completionTip: Customize the content in tooltips for completions.
// Is passed a single argument—the completion's data as returned by
// Tern—and may return a string, DOM node, or null to indicate that
// no tip should be shown. By default the docstring is shown.
// * typeTip: Like completionTip, but for the tooltips shown for type
// queries.
// * responseFilter: A function(doc, query, request, error, data) that
// will be applied to the Tern responses before treating them
//
//
// It is possible to run the Tern server in a web worker by specifying
// these additional options:
// * useWorker: Set to true to enable web worker mode. You'll probably
// want to feature detect the actual value you use here, for example
// !!window.Worker.
// * workerScript: The main script of the worker. Point this to
// wherever you are hosting worker.js from this directory.
// * workerDeps: An array of paths pointing (relative to workerScript)
// to the Acorn and Tern libraries and any Tern plugins you want to
// load. Or, if you minified those into a single script and included
// them in the workerScript, simply leave this undefined.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
// declare global: tern
CodeMirror.TernServer = function(options) {
var self = this;
this.options = options || {};
var plugins = this.options.plugins || (this.options.plugins = {});
if (!plugins.doc_comment) plugins.doc_comment = true;
this.docs = Object.create(null);
if (this.options.useWorker) {
this.server = new WorkerServer(this);
} else {
this.server = new tern.Server({
getFile: function(name, c) { return getFile(self, name, c); },
async: true,
defs: this.options.defs || [],
plugins: plugins
});
}
this.trackChange = function(doc, change) { trackChange(self, doc, change); };
this.cachedArgHints = null;
this.activeArgHints = null;
this.jumpStack = [];
this.getHint = function(cm, c) { return hint(self, cm, c); };
this.getHint.async = true;
};
CodeMirror.TernServer.prototype = {
addDoc: function(name, doc) {
var data = {doc: doc, name: name, changed: null};
this.server.addFile(name, docValue(this, data));
CodeMirror.on(doc, "change", this.trackChange);
return this.docs[name] = data;
},
delDoc: function(id) {
var found = resolveDoc(this, id);
if (!found) return;
CodeMirror.off(found.doc, "change", this.trackChange);
delete this.docs[found.name];
this.server.delFile(found.name);
},
hideDoc: function(id) {
closeArgHints(this);
var found = resolveDoc(this, id);
if (found && found.changed) sendDoc(this, found);
},
complete: function(cm) {
cm.showHint({hint: this.getHint});
},
showType: function(cm, pos, c) { showContextInfo(this, cm, pos, "type", c); },
showDocs: function(cm, pos, c) { showContextInfo(this, cm, pos, "documentation", c); },
updateArgHints: function(cm) { updateArgHints(this, cm); },
jumpToDef: function(cm) { jumpToDef(this, cm); },
jumpBack: function(cm) { jumpBack(this, cm); },
rename: function(cm) { rename(this, cm); },
selectName: function(cm) { selectName(this, cm); },
request: function (cm, query, c, pos) {
var self = this;
var doc = findDoc(this, cm.getDoc());
var request = buildRequest(this, doc, query, pos);
var extraOptions = request.query && this.options.queryOptions && this.options.queryOptions[request.query.type]
if (extraOptions) for (var prop in extraOptions) request.query[prop] = extraOptions[prop];
this.server.request(request, function (error, data) {
if (!error && self.options.responseFilter)
data = self.options.responseFilter(doc, query, request, error, data);
c(error, data);
});
},
destroy: function () {
closeArgHints(this)
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
}
};
var Pos = CodeMirror.Pos;
var cls = "CodeMirror-Tern-";
var bigDoc = 250;
function getFile(ts, name, c) {
var buf = ts.docs[name];
if (buf)
c(docValue(ts, buf));
else if (ts.options.getFile)
ts.options.getFile(name, c);
else
c(null);
}
function findDoc(ts, doc, name) {
for (var n in ts.docs) {
var cur = ts.docs[n];
if (cur.doc == doc) return cur;
}
if (!name) for (var i = 0;; ++i) {
n = "[doc" + (i || "") + "]";
if (!ts.docs[n]) { name = n; break; }
}
return ts.addDoc(name, doc);
}
function resolveDoc(ts, id) {
if (typeof id == "string") return ts.docs[id];
if (id instanceof CodeMirror) id = id.getDoc();
if (id instanceof CodeMirror.Doc) return findDoc(ts, id);
}
function trackChange(ts, doc, change) {
var data = findDoc(ts, doc);
var argHints = ts.cachedArgHints;
if (argHints && argHints.doc == doc && cmpPos(argHints.start, change.to) >= 0)
ts.cachedArgHints = null;
var changed = data.changed;
if (changed == null)
data.changed = changed = {from: change.from.line, to: change.from.line};
var end = change.from.line + (change.text.length - 1);
if (change.from.line < changed.to) changed.to = changed.to - (change.to.line - end);
if (end >= changed.to) changed.to = end + 1;
if (changed.from > change.from.line) changed.from = change.from.line;
if (doc.lineCount() > bigDoc && change.to - changed.from > 100) setTimeout(function() {
if (data.changed && data.changed.to - data.changed.from > 100) sendDoc(ts, data);
}, 200);
}
function sendDoc(ts, doc) {
ts.server.request({files: [{type: "full", name: doc.name, text: docValue(ts, doc)}]}, function(error) {
if (error) window.console.error(error);
else doc.changed = null;
});
}
// Completion
function hint(ts, cm, c) {
ts.request(cm, {type: "completions", types: true, docs: true, urls: true}, function(error, data) {
if (error) return showError(ts, cm, error);
var completions = [], after = "";
var from = data.start, to = data.end;
if (cm.getRange(Pos(from.line, from.ch - 2), from) == "[\"" &&
cm.getRange(to, Pos(to.line, to.ch + 2)) != "\"]")
after = "\"]";
for (var i = 0; i < data.completions.length; ++i) {
var completion = data.completions[i], className = typeToIcon(completion.type);
if (data.guess) className += " " + cls + "guess";
completions.push({text: completion.name + after,
displayText: completion.displayName || completion.name,
className: className,
data: completion});
}
var obj = {from: from, to: to, list: completions};
var tooltip = null;
CodeMirror.on(obj, "close", function() { remove(tooltip); });
CodeMirror.on(obj, "update", function() { remove(tooltip); });
CodeMirror.on(obj, "select", function(cur, node) {
remove(tooltip);
var content = ts.options.completionTip ? ts.options.completionTip(cur.data) : cur.data.doc;
if (content) {
tooltip = makeTooltip(node.parentNode.getBoundingClientRect().right + window.pageXOffset,
node.getBoundingClientRect().top + window.pageYOffset, content);
tooltip.className += " " + cls + "hint-doc";
}
});
c(obj);
});
}
function typeToIcon(type) {
var suffix;
if (type == "?") suffix = "unknown";
else if (type == "number" || type == "string" || type == "bool") suffix = type;
else if (/^fn\(/.test(type)) suffix = "fn";
else if (/^\[/.test(type)) suffix = "array";
else suffix = "object";
return cls + "completion " + cls + "completion-" + suffix;
}
// Type queries
function showContextInfo(ts, cm, pos, queryName, c) {
ts.request(cm, queryName, function(error, data) {
if (error) return showError(ts, cm, error);
if (ts.options.typeTip) {
var tip = ts.options.typeTip(data);
} else {
var tip = elt("span", null, elt("strong", null, data.type || "not found"));
if (data.doc)
tip.appendChild(document.createTextNode(" — " + data.doc));
if (data.url) {
tip.appendChild(document.createTextNode(" "));
var child = tip.appendChild(elt("a", null, "[docs]"));
child.href = data.url;
child.target = "_blank";
}
}
tempTooltip(cm, tip, ts);
if (c) c();
}, pos);
}
// Maintaining argument hints
function updateArgHints(ts, cm) {
closeArgHints(ts);
if (cm.somethingSelected()) return;
var state = cm.getTokenAt(cm.getCursor()).state;
var inner = CodeMirror.innerMode(cm.getMode(), state);
if (inner.mode.name != "javascript") return;
var lex = inner.state.lexical;
if (lex.info != "call") return;
var ch, argPos = lex.pos || 0, tabSize = cm.getOption("tabSize");
for (var line = cm.getCursor().line, e = Math.max(0, line - 9), found = false; line >= e; --line) {
var str = cm.getLine(line), extra = 0;
for (var pos = 0;;) {
var tab = str.indexOf("\t", pos);
if (tab == -1) break;
extra += tabSize - (tab + extra) % tabSize - 1;
pos = tab + 1;
}
ch = lex.column - extra;
if (str.charAt(ch) == "(") {found = true; break;}
}
if (!found) return;
var start = Pos(line, ch);
var cache = ts.cachedArgHints;
if (cache && cache.doc == cm.getDoc() && cmpPos(start, cache.start) == 0)
return showArgHints(ts, cm, argPos);
ts.request(cm, {type: "type", preferFunction: true, end: start}, function(error, data) {
if (error || !data.type || !(/^fn\(/).test(data.type)) return;
ts.cachedArgHints = {
start: start,
type: parseFnType(data.type),
name: data.exprName || data.name || "fn",
guess: data.guess,
doc: cm.getDoc()
};
showArgHints(ts, cm, argPos);
});
}
function showArgHints(ts, cm, pos) {
closeArgHints(ts);
var cache = ts.cachedArgHints, tp = cache.type;
var tip = elt("span", cache.guess ? cls + "fhint-guess" : null,
elt("span", cls + "fname", cache.name), "(");
for (var i = 0; i < tp.args.length; ++i) {
if (i) tip.appendChild(document.createTextNode(", "));
var arg = tp.args[i];
tip.appendChild(elt("span", cls + "farg" + (i == pos ? " " + cls + "farg-current" : ""), arg.name || "?"));
if (arg.type != "?") {
tip.appendChild(document.createTextNode(":\u00a0"));
tip.appendChild(elt("span", cls + "type", arg.type));
}
}
tip.appendChild(document.createTextNode(tp.rettype ? ") ->\u00a0" : ")"));
if (tp.rettype) tip.appendChild(elt("span", cls + "type", tp.rettype));
var place = cm.cursorCoords(null, "page");
var tooltip = ts.activeArgHints = makeTooltip(place.right + 1, place.bottom, tip)
setTimeout(function() {
tooltip.clear = onEditorActivity(cm, function() {
if (ts.activeArgHints == tooltip) closeArgHints(ts) })
}, 20)
}
function parseFnType(text) {
var args = [], pos = 3;
function skipMatching(upto) {
var depth = 0, start = pos;
for (;;) {
var next = text.charAt(pos);
if (upto.test(next) && !depth) return text.slice(start, pos);
if (/[{\[\(]/.test(next)) ++depth;
else if (/[}\]\)]/.test(next)) --depth;
++pos;
}
}
// Parse arguments
if (text.charAt(pos) != ")") for (;;) {
var name = text.slice(pos).match(/^([^, \(\[\{]+): /);
if (name) {
pos += name[0].length;
name = name[1];
}
args.push({name: name, type: skipMatching(/[\),]/)});
if (text.charAt(pos) == ")") break;
pos += 2;
}
var rettype = text.slice(pos).match(/^\) -> (.*)$/);
return {args: args, rettype: rettype && rettype[1]};
}
// Moving to the definition of something
function jumpToDef(ts, cm) {
function inner(varName) {
var req = {type: "definition", variable: varName || null};
var doc = findDoc(ts, cm.getDoc());
ts.server.request(buildRequest(ts, doc, req), function(error, data) {
if (error) return showError(ts, cm, error);
if (!data.file && data.url) { window.open(data.url); return; }
if (data.file) {
var localDoc = ts.docs[data.file], found;
if (localDoc && (found = findContext(localDoc.doc, data))) {
ts.jumpStack.push({file: doc.name,
start: cm.getCursor("from"),
end: cm.getCursor("to")});
moveTo(ts, doc, localDoc, found.start, found.end);
return;
}
}
showError(ts, cm, "Could not find a definition.");
});
}
if (!atInterestingExpression(cm))
dialog(cm, "Jump to variable", function(name) { if (name) inner(name); });
else
inner();
}
function jumpBack(ts, cm) {
var pos = ts.jumpStack.pop(), doc = pos && ts.docs[pos.file];
if (!doc) return;
moveTo(ts, findDoc(ts, cm.getDoc()), doc, pos.start, pos.end);
}
function moveTo(ts, curDoc, doc, start, end) {
doc.doc.setSelection(start, end);
if (curDoc != doc && ts.options.switchToDoc) {
closeArgHints(ts);
ts.options.switchToDoc(doc.name, doc.doc);
}
}
// The {line,ch} representation of positions makes this rather awkward.
function findContext(doc, data) {
var before = data.context.slice(0, data.contextOffset).split("\n");
var startLine = data.start.line - (before.length - 1);
var start = Pos(startLine, (before.length == 1 ? data.start.ch : doc.getLine(startLine).length) - before[0].length);
var text = doc.getLine(startLine).slice(start.ch);
for (var cur = startLine + 1; cur < doc.lineCount() && text.length < data.context.length; ++cur)
text += "\n" + doc.getLine(cur);
if (text.slice(0, data.context.length) == data.context) return data;
var cursor = doc.getSearchCursor(data.context, 0, false);
var nearest, nearestDist = Infinity;
while (cursor.findNext()) {
var from = cursor.from(), dist = Math.abs(from.line - start.line) * 10000;
if (!dist) dist = Math.abs(from.ch - start.ch);
if (dist < nearestDist) { nearest = from; nearestDist = dist; }
}
if (!nearest) return null;
if (before.length == 1)
nearest.ch += before[0].length;
else
nearest = Pos(nearest.line + (before.length - 1), before[before.length - 1].length);
if (data.start.line == data.end.line)
var end = Pos(nearest.line, nearest.ch + (data.end.ch - data.start.ch));
else
var end = Pos(nearest.line + (data.end.line - data.start.line), data.end.ch);
return {start: nearest, end: end};
}
function atInterestingExpression(cm) {
var pos = cm.getCursor("end"), tok = cm.getTokenAt(pos);
if (tok.start < pos.ch && tok.type == "comment") return false;
return /[\w)\]]/.test(cm.getLine(pos.line).slice(Math.max(pos.ch - 1, 0), pos.ch + 1));
}
// Variable renaming
function rename(ts, cm) {
var token = cm.getTokenAt(cm.getCursor());
if (!/\w/.test(token.string)) return showError(ts, cm, "Not at a variable");
dialog(cm, "New name for " + token.string, function(newName) {
ts.request(cm, {type: "rename", newName: newName, fullDocs: true}, function(error, data) {
if (error) return showError(ts, cm, error);
applyChanges(ts, data.changes);
});
});
}
function selectName(ts, cm) {
var name = findDoc(ts, cm.doc).name;
ts.request(cm, {type: "refs"}, function(error, data) {
if (error) return showError(ts, cm, error);
var ranges = [], cur = 0;
var curPos = cm.getCursor();
for (var i = 0; i < data.refs.length; i++) {
var ref = data.refs[i];
if (ref.file == name) {
ranges.push({anchor: ref.start, head: ref.end});
if (cmpPos(curPos, ref.start) >= 0 && cmpPos(curPos, ref.end) <= 0)
cur = ranges.length - 1;
}
}
cm.setSelections(ranges, cur);
});
}
var nextChangeOrig = 0;
function applyChanges(ts, changes) {
var perFile = Object.create(null);
for (var i = 0; i < changes.length; ++i) {
var ch = changes[i];
(perFile[ch.file] || (perFile[ch.file] = [])).push(ch);
}
for (var file in perFile) {
var known = ts.docs[file], chs = perFile[file];;
if (!known) continue;
chs.sort(function(a, b) { return cmpPos(b.start, a.start); });
var origin = "*rename" + (++nextChangeOrig);
for (var i = 0; i < chs.length; ++i) {
var ch = chs[i];
known.doc.replaceRange(ch.text, ch.start, ch.end, origin);
}
}
}
// Generic request-building helper
function buildRequest(ts, doc, query, pos) {
var files = [], offsetLines = 0, allowFragments = !query.fullDocs;
if (!allowFragments) delete query.fullDocs;
if (typeof query == "string") query = {type: query};
query.lineCharPositions = true;
if (query.end == null) {
query.end = pos || doc.doc.getCursor("end");
if (doc.doc.somethingSelected())
query.start = doc.doc.getCursor("start");
}
var startPos = query.start || query.end;
if (doc.changed) {
if (doc.doc.lineCount() > bigDoc && allowFragments !== false &&
doc.changed.to - doc.changed.from < 100 &&
doc.changed.from <= startPos.line && doc.changed.to > query.end.line) {
files.push(getFragmentAround(doc, startPos, query.end));
query.file = "#0";
var offsetLines = files[0].offsetLines;
if (query.start != null) query.start = Pos(query.start.line - -offsetLines, query.start.ch);
query.end = Pos(query.end.line - offsetLines, query.end.ch);
} else {
files.push({type: "full",
name: doc.name,
text: docValue(ts, doc)});
query.file = doc.name;
doc.changed = null;
}
} else {
query.file = doc.name;
}
for (var name in ts.docs) {
var cur = ts.docs[name];
if (cur.changed && cur != doc) {
files.push({type: "full", name: cur.name, text: docValue(ts, cur)});
cur.changed = null;
}
}
return {query: query, files: files};
}
function getFragmentAround(data, start, end) {
var doc = data.doc;
var minIndent = null, minLine = null, endLine, tabSize = 4;
for (var p = start.line - 1, min = Math.max(0, p - 50); p >= min; --p) {
var line = doc.getLine(p), fn = line.search(/\bfunction\b/);
if (fn < 0) continue;
var indent = CodeMirror.countColumn(line, null, tabSize);
if (minIndent != null && minIndent <= indent) continue;
minIndent = indent;
minLine = p;
}
if (minLine == null) minLine = min;
var max = Math.min(doc.lastLine(), end.line + 20);
if (minIndent == null || minIndent == CodeMirror.countColumn(doc.getLine(start.line), null, tabSize))
endLine = max;
else for (endLine = end.line + 1; endLine < max; ++endLine) {
var indent = CodeMirror.countColumn(doc.getLine(endLine), null, tabSize);
if (indent <= minIndent) break;
}
var from = Pos(minLine, 0);
return {type: "part",
name: data.name,
offsetLines: from.line,
text: doc.getRange(from, Pos(endLine, end.line == endLine ? null : 0))};
}
// Generic utilities
var cmpPos = CodeMirror.cmpPos;
function elt(tagname, cls /*, ... elts*/) {
var e = document.createElement(tagname);
if (cls) e.className = cls;
for (var i = 2; i < arguments.length; ++i) {
var elt = arguments[i];
if (typeof elt == "string") elt = document.createTextNode(elt);
e.appendChild(elt);
}
return e;
}
function dialog(cm, text, f) {
if (cm.openDialog)
cm.openDialog(text + ": <input type=text>", f);
else
f(prompt(text, ""));
}
// Tooltips
function tempTooltip(cm, content, ts) {
if (cm.state.ternTooltip) remove(cm.state.ternTooltip);
var where = cm.cursorCoords();
var tip = cm.state.ternTooltip = makeTooltip(where.right + 1, where.bottom, content);
function maybeClear() {
old = true;
if (!mouseOnTip) clear();
}
function clear() {
cm.state.ternTooltip = null;
if (tip.parentNode) fadeOut(tip)
clearActivity()
}
var mouseOnTip = false, old = false;
CodeMirror.on(tip, "mousemove", function() { mouseOnTip = true; });
CodeMirror.on(tip, "mouseout", function(e) {
var related = e.relatedTarget || e.toElement
if (!related || !CodeMirror.contains(tip, related)) {
if (old) clear();
else mouseOnTip = false;
}
});
setTimeout(maybeClear, ts.options.hintDelay ? ts.options.hintDelay : 1700);
var clearActivity = onEditorActivity(cm, clear)
}
function onEditorActivity(cm, f) {
cm.on("cursorActivity", f)
cm.on("blur", f)
cm.on("scroll", f)
cm.on("setDoc", f)
return function() {
cm.off("cursorActivity", f)
cm.off("blur", f)
cm.off("scroll", f)
cm.off("setDoc", f)
}
}
function makeTooltip(x, y, content) {
var node = elt("div", cls + "tooltip", content);
node.style.left = x + "px";
node.style.top = y + "px";
document.body.appendChild(node);
return node;
}
function remove(node) {
var p = node && node.parentNode;
if (p) p.removeChild(node);
}
function fadeOut(tooltip) {
tooltip.style.opacity = "0";
setTimeout(function() { remove(tooltip); }, 1100);
}
function showError(ts, cm, msg) {
if (ts.options.showError)
ts.options.showError(cm, msg);
else
tempTooltip(cm, String(msg), ts);
}
function closeArgHints(ts) {
if (ts.activeArgHints) {
if (ts.activeArgHints.clear) ts.activeArgHints.clear()
remove(ts.activeArgHints)
ts.activeArgHints = null
}
}
function docValue(ts, doc) {
var val = doc.doc.getValue();
if (ts.options.fileFilter) val = ts.options.fileFilter(val, doc.name, doc.doc);
return val;
}
// Worker wrapper
function WorkerServer(ts) {
var worker = ts.worker = new Worker(ts.options.workerScript);
worker.postMessage({type: "init",
defs: ts.options.defs,
plugins: ts.options.plugins,
scripts: ts.options.workerDeps});
var msgId = 0, pending = {};
function send(data, c) {
if (c) {
data.id = ++msgId;
pending[msgId] = c;
}
worker.postMessage(data);
}
worker.onmessage = function(e) {
var data = e.data;
if (data.type == "getFile") {
getFile(ts, data.name, function(err, text) {
send({type: "getFile", err: String(err), text: text, id: data.id});
});
} else if (data.type == "debug") {
window.console.log(data.message);
} else if (data.id && pending[data.id]) {
pending[data.id](data.err, data.body);
delete pending[data.id];
}
};
worker.onerror = function(e) {
for (var id in pending) pending[id](e);
pending = {};
};
this.addFile = function(name, text) { send({type: "add", name: name, text: text}); };
this.delFile = function(name) { send({type: "del", name: name}); };
this.request = function(body, c) { send({type: "req", body: body}, c); };
}
});

View file

@ -4,10 +4,6 @@
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'tern',
]
DevToolsModules(
'autocomplete.js',
'css-autocompleter.js',

View file

@ -1,13 +0,0 @@
This is the Tern code-analysis engine packaged for the Mozilla Project.
Tern is a stand-alone code-analysis engine for JavaScript. It is intended to be used with a code editor plugin to enhance the editor's support for intelligent JavaScript editing
# Upgrade
Currently used version is 0.6.2. To upgrade, download the latest release from http://ternjs.net/, and copy the files from lib/ into this directory.
You may also need to update the CodeMirror plugin found in devtools/client/shared/sourceeditor/codemirror/addon/tern, but it will most likely work without updating.
Replace instances of `require("acorn")` with `require("acorn/acorn")`
Replace instances of `acorn/dist/` with `acorn/`

File diff suppressed because it is too large Load diff

View file

@ -1,87 +0,0 @@
(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);
};
});

View file

@ -1,304 +0,0 @@
// Condensing an inferred set of types to a JSON description document.
// This code can be used to, after a library has been analyzed,
// extract the types defined in that library and dump them as a JSON
// structure (as parsed by def.js).
// The idea being that big libraries can be analyzed once, dumped, and
// then cheaply included in later analysis.
(function(root, mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
return mod(exports, require("./infer"));
if (typeof define == "function" && define.amd) // AMD
return define(["exports", "./infer"], mod);
mod(root.tern || (root.tern = {}), tern); // Plain browser env
})(this, function(exports, infer) {
"use strict";
exports.condense = function(origins, name, options) {
if (typeof origins == "string") origins = [origins];
var state = new State(origins, name || origins[0], options || {});
state.server.signal("preCondenseReach", state)
state.cx.topScope.path = "<top>";
state.cx.topScope.reached("", state);
for (var path in state.roots)
reach(state.roots[path], null, path, state);
for (var i = 0; i < state.patchUp.length; ++i)
patchUpSimpleInstance(state.patchUp[i], state);
state.server.signal("postCondenseReach", state)
for (var path in state.types)
store(createPath(path.split("."), state), state.types[path], state);
for (var path in state.altPaths)
storeAlt(path, state.altPaths[path], state);
var hasDef = false;
for (var _def in state.output["!define"]) { hasDef = true; break; }
if (!hasDef) delete state.output["!define"];
state.server.signal("postCondense", state)
return simplify(state.output, state.options.sortOutput);
};
function State(origins, name, options) {
this.origins = origins;
this.cx = infer.cx();
this.server = options.server || this.cx.parent || {signal: function() {}}
this.maxOrigin = -Infinity;
for (var i = 0; i < origins.length; ++i)
this.maxOrigin = Math.max(this.maxOrigin, this.cx.origins.indexOf(origins[i]));
this.output = {"!name": name, "!define": {}};
this.options = options;
this.types = Object.create(null);
this.altPaths = Object.create(null);
this.patchUp = [];
this.roots = Object.create(null);
}
State.prototype.isTarget = function(origin) {
return this.origins.indexOf(origin) > -1;
};
State.prototype.getSpan = function(node) {
if (this.options.spans == false || !this.isTarget(node.origin)) return null;
if (node.span) return node.span;
var srv = this.cx.parent, file;
if (!srv || !node.originNode || !(file = srv.findFile(node.origin))) return null;
var start = node.originNode.start, end = node.originNode.end;
var pStart = file.asLineChar(start), pEnd = file.asLineChar(end);
return start + "[" + pStart.line + ":" + pStart.ch + "]-" +
end + "[" + pEnd.line + ":" + pEnd.ch + "]";
};
function pathLen(path) {
var len = 1, pos = 0, dot;
while ((dot = path.indexOf(".", pos)) != -1) {
pos = dot + 1;
len += path.charAt(pos) == "!" ? 10 : 1;
}
return len;
}
function hop(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
function isSimpleInstance(o) {
return o.proto && !(o instanceof infer.Fn) && o.proto != infer.cx().protos.Object &&
o.proto.hasCtor && !o.hasCtor;
}
function reach(type, path, id, state, byName) {
var actual = type.getType(false);
if (!actual) return;
var orig = type.origin || actual.origin, relevant = false;
if (orig) {
var origPos = state.cx.origins.indexOf(orig);
// This is a path that is newer than the code we are interested in.
if (origPos > state.maxOrigin) return;
relevant = state.isTarget(orig);
}
var newPath = path ? path + "." + id : id, oldPath = actual.path;
var shorter = !oldPath || pathLen(oldPath) > pathLen(newPath);
if (shorter) {
if (!(actual instanceof infer.Prim)) actual.path = newPath;
if (actual.reached(newPath, state, !relevant) && relevant) {
var data = state.types[oldPath];
if (data) {
delete state.types[oldPath];
state.altPaths[oldPath] = actual;
} else data = {type: actual};
data.span = state.getSpan(type) || (actual != type && state.isTarget(actual.origin) && state.getSpan(actual)) || data.span;
data.doc = type.doc || (actual != type && state.isTarget(actual.origin) && actual.doc) || data.doc;
data.data = actual.metaData;
data.byName = data.byName == null ? !!byName : data.byName && byName;
state.types[newPath] = data;
}
} else {
if (relevant) state.altPaths[newPath] = actual;
}
}
function reachByName(aval, path, id, state) {
var type = aval.getType();
if (type) reach(type, path, id, state, true);
}
infer.Prim.prototype.reached = function() {return true;};
infer.Arr.prototype.reached = function(path, state, concrete) {
if (concrete) return true
if (this.tuple) {
for (var i = 0; i < this.tuple; i++)
reachByName(this.getProp(String(i)), path, String(i), state)
} else {
reachByName(this.getProp("<i>"), path, "<i>", state)
}
return true;
};
infer.Fn.prototype.reached = function(path, state, concrete) {
infer.Obj.prototype.reached.call(this, path, state, concrete);
if (!concrete) {
for (var i = 0; i < this.args.length; ++i)
reachByName(this.args[i], path, "!" + i, state);
reachByName(this.retval, path, "!ret", state);
}
return true;
};
infer.Obj.prototype.reached = function(path, state, concrete) {
if (isSimpleInstance(this) && !this.condenseForceInclude) {
if (!state.patchUp.includes(this)) state.patchUp.push(this);
return true;
} else if (this.proto && !concrete) {
reach(this.proto, path, "!proto", state);
}
var hasProps = false;
for (var prop in this.props) {
reach(this.props[prop], path, prop, state);
hasProps = true;
}
if (!hasProps && !this.condenseForceInclude && !(this instanceof infer.Fn)) {
this.nameOverride = "?";
return false;
}
return true;
};
function patchUpSimpleInstance(obj, state) {
var path = obj.proto.hasCtor.path;
if (path) {
obj.nameOverride = "+" + path;
} else {
path = obj.path;
}
for (var prop in obj.props)
reach(obj.props[prop], path, prop, state);
}
function createPath(parts, state) {
var base = state.output, defs = state.output["!define"];
for (var i = 0, path; i < parts.length; ++i) {
var part = parts[i];
path = path ? path + "." + part : part;
var me = state.types[path];
if (part.charAt(0) == "!" || me && me.byName) {
if (hop(defs, path)) base = defs[path];
else defs[path] = base = {};
} else {
if (hop(base, parts[i])) base = base[part];
else base = base[part] = {};
}
}
return base;
}
function store(out, info, state) {
var name = typeName(info.type);
if (name != info.type.path && name != "?") {
out["!type"] = name;
} else if (info.type.proto && info.type.proto != state.cx.protos.Object) {
var protoName = typeName(info.type.proto);
if (protoName != "?") out["!proto"] = protoName;
}
if (info.span) out["!span"] = info.span;
if (info.doc) out["!doc"] = info.doc;
if (info.data) out["!data"] = info.data;
}
function storeAlt(path, type, state) {
var parts = path.split("."), last = parts.pop();
if (last[0] == "!") return;
var known = state.types[parts.join(".")];
var base = createPath(parts, state);
if (known && known.type.constructor != infer.Obj) return;
if (!hop(base, last)) base[last] = type.nameOverride || type.path;
}
var typeNameStack = [];
function typeName(value) {
var isType = value instanceof infer.Type;
if (isType) {
if (typeNameStack.indexOf(value) > -1)
return value.path || "?";
typeNameStack.push(value);
}
var name = value.typeName();
if (isType) typeNameStack.pop();
return name;
}
infer.AVal.prototype.typeName = function() {
if (this.types.length == 0) return "?";
if (this.types.length == 1) return typeName(this.types[0]);
var simplified = infer.simplifyTypes(this.types);
if (simplified.length > 2) return "?";
for (var strs = [], i = 0; i < simplified.length; i++)
strs.push(typeName(simplified[i]));
return strs.join("|");
};
infer.ANull.typeName = function() { return "?"; };
infer.Prim.prototype.typeName = function() { return this.name; };
infer.Sym.prototype.typeName = function() { return this.asPropName }
infer.Arr.prototype.typeName = function() {
if (!this.tuple) return "[" + typeName(this.getProp("<i>")) + "]"
var content = []
for (var i = 0; i < this.tuple; i++)
content.push(typeName(this.getProp(String(i))))
return "[" + content.join(", ") + "]"
};
infer.Fn.prototype.typeName = function() {
var out = this.generator ? "fn*(" : "fn(";
for (var i = 0; i < this.args.length; ++i) {
if (i) out += ", ";
var name = this.argNames[i];
if (name && name != "?") out += name + ": ";
out += typeName(this.args[i]);
}
out += ")";
if (this.computeRetSource)
out += " -> " + this.computeRetSource;
else if (!this.retval.isEmpty())
out += " -> " + typeName(this.retval);
return out;
};
infer.Obj.prototype.typeName = function() {
if (this.nameOverride) return this.nameOverride;
if (!this.path) return "?";
return this.path;
};
function simplify(data, sort) {
if (typeof data != "object") return data;
var sawType = false, sawOther = false;
for (var prop in data) {
if (prop == "!type") sawType = true;
else sawOther = true;
if (prop != "!data")
data[prop] = simplify(data[prop], sort);
}
if (sawType && !sawOther) return data["!type"];
return sort ? sortObject(data) : data;
}
function sortObject(obj) {
var props = [], out = {};
for (var prop in obj) props.push(prop);
props.sort();
for (var i = 0; i < props.length; ++i) {
var prop = props[i];
out[prop] = obj[prop];
}
return out;
}
});

View file

@ -1,656 +0,0 @@
// Type description parser
//
// Type description JSON files (such as ecma5.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) }))
}
}
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 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.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 "<top>": return cx.topScope;
}
if (cx.localDefs && spec in cx.localDefs) return cx.localDefs[spec];
return parsePath(spec);
},
parsePoly: function(base) {
var propName = "<i>", 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 parseType(spec, name, base, forceNew) {
var type = new TypeParser(spec, null, base, forceNew).parseType(false, name, true);
if (/^fn\(/.test(spec)) for (var i = 0; i < type.args.length; ++i) (function(i) {
var arg = type.args[i];
if (arg instanceof infer.Fn && arg.args && arg.args.length) addEffect(type, function(_self, fArgs) {
var fArg = fArgs[i];
if (fArg) fArg.propagate(new infer.IsCallee(infer.cx().topScope, arg.args, null, infer.ANull));
});
})(i);
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 != "<i>")
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) {
var propVal = (prop == "prototype" && base instanceof infer.Fn) ? base.getProp(prop) : base.props[prop];
if (!propVal || propVal.isEmpty())
base = infer.ANull;
else
base = propVal.types[0];
}
}
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 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("<i>");
for (var i = 0; i < args.length; ++i) args[i].propagate(content);
}
return arr;
});
infer.registerFunction("Promise_ctor", function(_self, args, argNodes) {
var defs6 = infer.cx().definitions.ecma6
if (!defs6 || args.length < 1) return infer.ANull;
var self = new infer.Obj(defs6["Promise.prototype"]);
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 = defs6.Promise_reject;
args[0].propagate(new infer.IsCallee(infer.ANull, [exec, reject], null, infer.ANull));
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 defs6 = infer.cx().definitions.ecma6
if (!fn || !defs6) return self;
var result = new infer.Obj(defs6["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.length && argNodes[0].type == "Literal" && typeof argNodes[0].value == "string")
return infer.getSymbol(argNodes[0].value)
else
return infer.ANull
})
return exports;
});

View file

@ -1,950 +0,0 @@
module.exports = {
"!name": "ecma5",
"!define": {"Error.prototype": "Error.prototype"},
"Infinity": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Infinity",
"!doc": "A numeric value representing infinity."
},
"undefined": {
"!type": "?",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/undefined",
"!doc": "The value undefined."
},
"NaN": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/NaN",
"!doc": "A value representing Not-A-Number."
},
"Object": {
"!type": "fn()",
"getPrototypeOf": {
"!type": "fn(obj: ?) -> ?",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getPrototypeOf",
"!doc": "Returns the prototype (i.e. the internal prototype) of the specified object."
},
"create": {
"!type": "fn(proto: ?) -> !custom:Object_create",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create",
"!doc": "Creates a new object with the specified prototype object and properties."
},
"defineProperty": {
"!type": "fn(obj: ?, prop: string, desc: ?)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty",
"!doc": "Defines a new property directly on an object, or modifies an existing property on an object, and returns the object. If you want to see how to use the Object.defineProperty method with a binary-flags-like syntax, see this article."
},
"defineProperties": {
"!type": "fn(obj: ?, props: ?)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty",
"!doc": "Defines a new property directly on an object, or modifies an existing property on an object, and returns the object. If you want to see how to use the Object.defineProperty method with a binary-flags-like syntax, see this article."
},
"getOwnPropertyDescriptor": {
"!type": "fn(obj: ?, prop: string) -> ?",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor",
"!doc": "Returns a property descriptor for an own property (that is, one directly present on an object, not present by dint of being along an object's prototype chain) of a given object."
},
"keys": {
"!type": "fn(obj: ?) -> [string]",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys",
"!doc": "Returns an array of a given object's own enumerable properties, in the same order as that provided by a for-in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well)."
},
"getOwnPropertyNames": {
"!type": "fn(obj: ?) -> [string]",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames",
"!doc": "Returns an array of all properties (enumerable or not) found directly upon a given object."
},
"seal": {
"!type": "fn(obj: ?)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/seal",
"!doc": "Seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable."
},
"isSealed": {
"!type": "fn(obj: ?) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/isSealed",
"!doc": "Determine if an object is sealed."
},
"freeze": {
"!type": "fn(obj: ?)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/freeze",
"!doc": "Freezes an object: that is, prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed. In essence the object is made effectively immutable. The method returns the object being frozen."
},
"isFrozen": {
"!type": "fn(obj: ?) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/isFrozen",
"!doc": "Determine if an object is frozen."
},
"prototype": {
"!stdProto": "Object",
"toString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/toString",
"!doc": "Returns a string representing the object."
},
"toLocaleString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/toLocaleString",
"!doc": "Returns a string representing the object. This method is meant to be overriden by derived objects for locale-specific purposes."
},
"valueOf": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/valueOf",
"!doc": "Returns the primitive value of the specified object"
},
"hasOwnProperty": {
"!type": "fn(prop: string) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/hasOwnProperty",
"!doc": "Returns a boolean indicating whether the object has the specified property."
},
"propertyIsEnumerable": {
"!type": "fn(prop: string) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/propertyIsEnumerable",
"!doc": "Returns a Boolean indicating whether the specified property is enumerable."
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object",
"!doc": "Creates an object wrapper."
},
"Function": {
"!type": "fn(body: string) -> fn()",
"prototype": {
"!stdProto": "Function",
"apply": {
"!type": "fn(this: ?, args: [?])",
"!effects": [
"call and return !this this=!0 !1.<i> !1.<i> !1.<i>"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply",
"!doc": "Calls a function with a given this value and arguments provided as an array (or an array like object)."
},
"call": {
"!type": "fn(this: ?, args?: ?) -> !this.!ret",
"!effects": [
"call and return !this this=!0 !1 !2 !3 !4"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/call",
"!doc": "Calls a function with a given this value and arguments provided individually."
},
"bind": {
"!type": "fn(this: ?, args?: ?) -> !custom:Function_bind",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind",
"!doc": "Creates a new function that, when called, has its this keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function was called."
},
"prototype": "?"
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function",
"!doc": "Every function in JavaScript is actually a Function object."
},
"Array": {
"!type": "fn(size: number) -> !custom:Array_ctor",
"isArray": {
"!type": "fn(value: ?) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/isArray",
"!doc": "Returns true if an object is an array, false if it is not."
},
"prototype": {
"!stdProto": "Array",
"length": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/length",
"!doc": "An unsigned, 32-bit integer that specifies the number of elements in an array."
},
"concat": {
"!type": "fn(other: [?]) -> !this",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/concat",
"!doc": "Returns a new array comprised of this array joined with other array(s) and/or value(s)."
},
"join": {
"!type": "fn(separator?: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/join",
"!doc": "Joins all elements of an array into a string."
},
"splice": {
"!type": "fn(pos: number, amount: number)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/splice",
"!doc": "Changes the content of an array, adding new elements while removing old elements."
},
"pop": {
"!type": "fn() -> !this.<i>",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/pop",
"!doc": "Removes the last element from an array and returns that element."
},
"push": {
"!type": "fn(newelt: ?) -> number",
"!effects": [
"propagate !0 !this.<i>"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/push",
"!doc": "Mutates an array by appending the given elements and returning the new length of the array."
},
"shift": {
"!type": "fn() -> !this.<i>",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/shift",
"!doc": "Removes the first element from an array and returns that element. This method changes the length of the array."
},
"unshift": {
"!type": "fn(newelt: ?) -> number",
"!effects": [
"propagate !0 !this.<i>"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/unshift",
"!doc": "Adds one or more elements to the beginning of an array and returns the new length of the array."
},
"slice": {
"!type": "fn(from: number, to?: number) -> !this",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice",
"!doc": "Returns a shallow copy of a portion of an array."
},
"reverse": {
"!type": "fn()",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/reverse",
"!doc": "Reverses an array in place. The first array element becomes the last and the last becomes the first."
},
"sort": {
"!type": "fn(compare?: fn(a: ?, b: ?) -> number)",
"!effects": [
"call !0 !this.<i> !this.<i>"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/sort",
"!doc": "Sorts the elements of an array in place and returns the array."
},
"indexOf": {
"!type": "fn(elt: ?, from?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/indexOf",
"!doc": "Returns the first index at which a given element can be found in the array, or -1 if it is not present."
},
"lastIndexOf": {
"!type": "fn(elt: ?, from?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/lastIndexOf",
"!doc": "Returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards, starting at fromIndex."
},
"every": {
"!type": "fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> bool",
"!effects": [
"call !0 this=!1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/every",
"!doc": "Tests whether all elements in the array pass the test implemented by the provided function."
},
"some": {
"!type": "fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> bool",
"!effects": [
"call !0 this=!1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/some",
"!doc": "Tests whether some element in the array passes the test implemented by the provided function."
},
"filter": {
"!type": "fn(test: fn(elt: ?, i: number) -> bool, context?: ?) -> !this",
"!effects": [
"call !0 this=!1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/filter",
"!doc": "Creates a new array with all elements that pass the test implemented by the provided function."
},
"forEach": {
"!type": "fn(f: fn(elt: ?, i: number), context?: ?)",
"!effects": [
"call !0 this=!1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach",
"!doc": "Executes a provided function once per array element."
},
"map": {
"!type": "fn(f: fn(elt: ?, i: number) -> ?, context?: ?) -> [!0.!ret]",
"!effects": [
"call !0 this=!1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/map",
"!doc": "Creates a new array with the results of calling a provided function on every element in this array."
},
"reduce": {
"!type": "fn(combine: fn(sum: ?, elt: ?, i: number) -> ?, init?: ?) -> !0.!ret",
"!effects": [
"call !0 !1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/Reduce",
"!doc": "Apply a function against an accumulator and each value of the array (from left-to-right) as to reduce it to a single value."
},
"reduceRight": {
"!type": "fn(combine: fn(sum: ?, elt: ?, i: number) -> ?, init?: ?) -> !0.!ret",
"!effects": [
"call !0 !1 !this.<i> number"
],
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/ReduceRight",
"!doc": "Apply a function simultaneously against two values of the array (from right-to-left) as to reduce it to a single value."
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array",
"!doc": "The JavaScript Array global object is a constructor for arrays, which are high-level, list-like objects."
},
"String": {
"!type": "fn(value: ?) -> string",
"fromCharCode": {
"!type": "fn(code: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/fromCharCode",
"!doc": "Returns a string created by using the specified sequence of Unicode values."
},
"prototype": {
"!stdProto": "String",
"length": {
"!type": "number",
"!url": "https://developer.mozilla.org/en/docs/JavaScript/Reference/Global_Objects/String/length",
"!doc": "Represents the length of a string."
},
"<i>": "string",
"charAt": {
"!type": "fn(i: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/charAt",
"!doc": "Returns the specified character from a string."
},
"charCodeAt": {
"!type": "fn(i: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/charCodeAt",
"!doc": "Returns the numeric Unicode value of the character at the given index (except for unicode codepoints > 0x10000)."
},
"indexOf": {
"!type": "fn(char: string, from?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/indexOf",
"!doc": "Returns the index within the calling String object of the first occurrence of the specified value, starting the search at fromIndex,\nreturns -1 if the value is not found."
},
"lastIndexOf": {
"!type": "fn(char: string, from?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/lastIndexOf",
"!doc": "Returns the index within the calling String object of the last occurrence of the specified value, or -1 if not found. The calling string is searched backward, starting at fromIndex."
},
"substring": {
"!type": "fn(from: number, to?: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/substring",
"!doc": "Returns a subset of a string between one index and another, or through the end of the string."
},
"substr": {
"!type": "fn(from: number, length?: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/substr",
"!doc": "Returns the characters in a string beginning at the specified location through the specified number of characters."
},
"slice": {
"!type": "fn(from: number, to?: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/slice",
"!doc": "Extracts a section of a string and returns a new string."
},
"trim": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/Trim",
"!doc": "Removes whitespace from both ends of the string."
},
"trimLeft": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/TrimLeft",
"!doc": "Removes whitespace from the left end of the string."
},
"trimRight": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/TrimRight",
"!doc": "Removes whitespace from the right end of the string."
},
"toUpperCase": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toUpperCase",
"!doc": "Returns the calling string value converted to uppercase."
},
"toLowerCase": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLowerCase",
"!doc": "Returns the calling string value converted to lowercase."
},
"toLocaleUpperCase": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLocaleUpperCase",
"!doc": "Returns the calling string value converted to upper case, according to any locale-specific case mappings."
},
"toLocaleLowerCase": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/toLocaleLowerCase",
"!doc": "Returns the calling string value converted to lower case, according to any locale-specific case mappings."
},
"split": {
"!type": "fn(pattern: string) -> [string]",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/split",
"!doc": "Splits a String object into an array of strings by separating the string into substrings."
},
"concat": {
"!type": "fn(other: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/concat",
"!doc": "Combines the text of two or more strings and returns a new string."
},
"localeCompare": {
"!type": "fn(other: string) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/localeCompare",
"!doc": "Returns a number indicating whether a reference string comes before or after or is the same as the given string in sort order."
},
"match": {
"!type": "fn(pattern: +RegExp) -> [string]",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/match",
"!doc": "Used to retrieve the matches when matching a string against a regular expression."
},
"replace": {
"!type": "fn(pattern: +RegExp, replacement: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/replace",
"!doc": "Returns a new string with some or all matches of a pattern replaced by a replacement. The pattern can be a string or a RegExp, and the replacement can be a string or a function to be called for each match."
},
"search": {
"!type": "fn(pattern: +RegExp) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String/search",
"!doc": "Executes the search for a match between a regular expression and this String object."
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/String",
"!doc": "The String global object is a constructor for strings, or a sequence of characters."
},
"Number": {
"!type": "fn(value: ?) -> number",
"MAX_VALUE": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/MAX_VALUE",
"!doc": "The maximum numeric value representable in JavaScript."
},
"MIN_VALUE": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/MIN_VALUE",
"!doc": "The smallest positive numeric value representable in JavaScript."
},
"POSITIVE_INFINITY": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/POSITIVE_INFINITY",
"!doc": "A value representing the positive Infinity value."
},
"NEGATIVE_INFINITY": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/NEGATIVE_INFINITY",
"!doc": "A value representing the negative Infinity value."
},
"prototype": {
"!stdProto": "Number",
"toString": {
"!type": "fn(radix?: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toString",
"!doc": "Returns a string representing the specified Number object"
},
"toFixed": {
"!type": "fn(digits: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toFixed",
"!doc": "Formats a number using fixed-point notation"
},
"toExponential": {
"!type": "fn(digits: number) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number/toExponential",
"!doc": "Returns a string representing the Number object in exponential notation"
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Number",
"!doc": "The Number JavaScript object is a wrapper object allowing you to work with numerical values. A Number object is created using the Number() constructor."
},
"Boolean": {
"!type": "fn(value: ?) -> bool",
"prototype": {
"!stdProto": "Boolean"
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Boolean",
"!doc": "The Boolean object is an object wrapper for a boolean value."
},
"RegExp": {
"!type": "fn(source: string, flags?: string)",
"prototype": {
"!stdProto": "RegExp",
"exec": {
"!type": "fn(input: string) -> [string]",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/exec",
"!doc": "Executes a search for a match in a specified string. Returns a result array, or null."
},
"compile": {
"!type": "fn(source: string, flags?: string)",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp",
"!doc": "Creates a regular expression object for matching text with a pattern."
},
"test": {
"!type": "fn(input: string) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/test",
"!doc": "Executes the search for a match between a regular expression and a specified string. Returns true or false."
},
"global": {
"!type": "bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp",
"!doc": "Creates a regular expression object for matching text with a pattern."
},
"ignoreCase": {
"!type": "bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp",
"!doc": "Creates a regular expression object for matching text with a pattern."
},
"multiline": {
"!type": "bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/multiline",
"!doc": "Reflects whether or not to search in strings across multiple lines.\n"
},
"source": {
"!type": "string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/source",
"!doc": "A read-only property that contains the text of the pattern, excluding the forward slashes.\n"
},
"lastIndex": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp/lastIndex",
"!doc": "A read/write integer property that specifies the index at which to start the next match."
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RegExp",
"!doc": "Creates a regular expression object for matching text with a pattern."
},
"Date": {
"!type": "fn(ms: number)",
"parse": {
"!type": "fn(source: string) -> +Date",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/parse",
"!doc": "Parses a string representation of a date, and returns the number of milliseconds since January 1, 1970, 00:00:00 UTC."
},
"UTC": {
"!type": "fn(year: number, month: number, date: number, hour?: number, min?: number, sec?: number, ms?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/UTC",
"!doc": "Accepts the same parameters as the longest form of the constructor, and returns the number of milliseconds in a Date object since January 1, 1970, 00:00:00, universal time."
},
"now": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/now",
"!doc": "Returns the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC."
},
"prototype": {
"toUTCString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toUTCString",
"!doc": "Converts a date to a string, using the universal time convention."
},
"toISOString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toISOString",
"!doc": "JavaScript provides a direct way to convert a date object into a string in ISO format, the ISO 8601 Extended Format."
},
"toDateString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toDateString",
"!doc": "Returns the date portion of a Date object in human readable form in American English."
},
"toTimeString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toTimeString",
"!doc": "Returns the time portion of a Date object in human readable form in American English."
},
"toLocaleDateString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleDateString",
"!doc": "Converts a date to a string, returning the \"date\" portion using the operating system's locale's conventions.\n"
},
"toLocaleTimeString": {
"!type": "fn() -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString",
"!doc": "Converts a date to a string, returning the \"time\" portion using the current locale's conventions."
},
"getTime": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getTime",
"!doc": "Returns the numeric value corresponding to the time for the specified date according to universal time."
},
"getFullYear": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getFullYear",
"!doc": "Returns the year of the specified date according to local time."
},
"getYear": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getYear",
"!doc": "Returns the year in the specified date according to local time."
},
"getMonth": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMonth",
"!doc": "Returns the month in the specified date according to local time."
},
"getUTCMonth": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCMonth",
"!doc": "Returns the month of the specified date according to universal time.\n"
},
"getDate": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getDate",
"!doc": "Returns the day of the month for the specified date according to local time."
},
"getUTCDate": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCDate",
"!doc": "Returns the day (date) of the month in the specified date according to universal time.\n"
},
"getDay": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getDay",
"!doc": "Returns the day of the week for the specified date according to local time."
},
"getUTCDay": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCDay",
"!doc": "Returns the day of the week in the specified date according to universal time.\n"
},
"getHours": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getHours",
"!doc": "Returns the hour for the specified date according to local time."
},
"getUTCHours": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCHours",
"!doc": "Returns the hours in the specified date according to universal time.\n"
},
"getMinutes": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMinutes",
"!doc": "Returns the minutes in the specified date according to local time."
},
"getUTCMinutes": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date",
"!doc": "Creates JavaScript Date instances which let you work with dates and times."
},
"getSeconds": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getSeconds",
"!doc": "Returns the seconds in the specified date according to local time."
},
"getUTCSeconds": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCSeconds",
"!doc": "Returns the seconds in the specified date according to universal time.\n"
},
"getMilliseconds": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getMilliseconds",
"!doc": "Returns the milliseconds in the specified date according to local time."
},
"getUTCMilliseconds": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getUTCMilliseconds",
"!doc": "Returns the milliseconds in the specified date according to universal time.\n"
},
"getTimezoneOffset": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset",
"!doc": "Returns the time-zone offset from UTC, in minutes, for the current locale."
},
"setTime": {
"!type": "fn(date: +Date) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setTime",
"!doc": "Sets the Date object to the time represented by a number of milliseconds since January 1, 1970, 00:00:00 UTC.\n"
},
"setFullYear": {
"!type": "fn(year: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setFullYear",
"!doc": "Sets the full year for a specified date according to local time.\n"
},
"setUTCFullYear": {
"!type": "fn(year: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCFullYear",
"!doc": "Sets the full year for a specified date according to universal time.\n"
},
"setMonth": {
"!type": "fn(month: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMonth",
"!doc": "Set the month for a specified date according to local time."
},
"setUTCMonth": {
"!type": "fn(month: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMonth",
"!doc": "Sets the month for a specified date according to universal time.\n"
},
"setDate": {
"!type": "fn(day: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setDate",
"!doc": "Sets the day of the month for a specified date according to local time."
},
"setUTCDate": {
"!type": "fn(day: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCDate",
"!doc": "Sets the day of the month for a specified date according to universal time.\n"
},
"setHours": {
"!type": "fn(hour: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setHours",
"!doc": "Sets the hours for a specified date according to local time, and returns the number of milliseconds since 1 January 1970 00:00:00 UTC until the time represented by the updated Date instance."
},
"setUTCHours": {
"!type": "fn(hour: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCHours",
"!doc": "Sets the hour for a specified date according to universal time.\n"
},
"setMinutes": {
"!type": "fn(min: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMinutes",
"!doc": "Sets the minutes for a specified date according to local time."
},
"setUTCMinutes": {
"!type": "fn(min: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMinutes",
"!doc": "Sets the minutes for a specified date according to universal time.\n"
},
"setSeconds": {
"!type": "fn(sec: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setSeconds",
"!doc": "Sets the seconds for a specified date according to local time."
},
"setUTCSeconds": {
"!type": "fn(sec: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCSeconds",
"!doc": "Sets the seconds for a specified date according to universal time.\n"
},
"setMilliseconds": {
"!type": "fn(ms: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setMilliseconds",
"!doc": "Sets the milliseconds for a specified date according to local time.\n"
},
"setUTCMilliseconds": {
"!type": "fn(ms: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/setUTCMilliseconds",
"!doc": "Sets the milliseconds for a specified date according to universal time.\n"
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date",
"!doc": "Creates JavaScript Date instances which let you work with dates and times."
},
"Error": {
"!type": "fn(message: string)",
"prototype": {
"name": {
"!type": "string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error/name",
"!doc": "A name for the type of error."
},
"message": {
"!type": "string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error/message",
"!doc": "A human-readable description of the error."
}
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Error",
"!doc": "Creates an error object."
},
"SyntaxError": {
"!type": "fn(message: string)",
"prototype": "Error.prototype",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/SyntaxError",
"!doc": "Represents an error when trying to interpret syntactically invalid code."
},
"ReferenceError": {
"!type": "fn(message: string)",
"prototype": "Error.prototype",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/ReferenceError",
"!doc": "Represents an error when a non-existent variable is referenced."
},
"URIError": {
"!type": "fn(message: string)",
"prototype": "Error.prototype",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/URIError",
"!doc": "Represents an error when a malformed URI is encountered."
},
"EvalError": {
"!type": "fn(message: string)",
"prototype": "Error.prototype",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/EvalError",
"!doc": "Represents an error regarding the eval function."
},
"RangeError": {
"!type": "fn(message: string)",
"prototype": "Error.prototype",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/RangeError",
"!doc": "Represents an error when a number is not within the correct range allowed."
},
"parseInt": {
"!type": "fn(string: string, radix?: number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseInt",
"!doc": "Parses a string argument and returns an integer of the specified radix or base."
},
"parseFloat": {
"!type": "fn(string: string) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/parseFloat",
"!doc": "Parses a string argument and returns a floating point number."
},
"isNaN": {
"!type": "fn(value: number) -> bool",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/isNaN",
"!doc": "Determines whether a value is NaN or not. Be careful, this function is broken. You may be interested in ECMAScript 6 Number.isNaN."
},
"eval": {
"!type": "fn(code: string) -> ?",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/eval",
"!doc": "Evaluates JavaScript code represented as a string."
},
"encodeURI": {
"!type": "fn(uri: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURI",
"!doc": "Encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two \"surrogate\" characters)."
},
"encodeURIComponent": {
"!type": "fn(uri: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent",
"!doc": "Encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two \"surrogate\" characters)."
},
"decodeURI": {
"!type": "fn(uri: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/decodeURI",
"!doc": "Decodes a Uniform Resource Identifier (URI) previously created by encodeURI or by a similar routine."
},
"decodeURIComponent": {
"!type": "fn(uri: string) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/decodeURIComponent",
"!doc": "Decodes a Uniform Resource Identifier (URI) component previously created by encodeURIComponent or by a similar routine."
},
"Math": {
"E": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/E",
"!doc": "The base of natural logarithms, e, approximately 2.718."
},
"LN2": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LN2",
"!doc": "The natural logarithm of 2, approximately 0.693."
},
"LN10": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LN10",
"!doc": "The natural logarithm of 10, approximately 2.302."
},
"LOG2E": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LOG2E",
"!doc": "The base 2 logarithm of E (approximately 1.442)."
},
"LOG10E": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/LOG10E",
"!doc": "The base 10 logarithm of E (approximately 0.434)."
},
"SQRT1_2": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/SQRT1_2",
"!doc": "The square root of 1/2; equivalently, 1 over the square root of 2, approximately 0.707."
},
"SQRT2": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/SQRT2",
"!doc": "The square root of 2, approximately 1.414."
},
"PI": {
"!type": "number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/PI",
"!doc": "The ratio of the circumference of a circle to its diameter, approximately 3.14159."
},
"abs": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/abs",
"!doc": "Returns the absolute value of a number."
},
"cos": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/cos",
"!doc": "Returns the cosine of a number."
},
"sin": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/sin",
"!doc": "Returns the sine of a number."
},
"tan": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/tan",
"!doc": "Returns the tangent of a number."
},
"acos": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/acos",
"!doc": "Returns the arccosine (in radians) of a number."
},
"asin": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/asin",
"!doc": "Returns the arcsine (in radians) of a number."
},
"atan": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan",
"!doc": "Returns the arctangent (in radians) of a number."
},
"atan2": {
"!type": "fn(number, number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/atan2",
"!doc": "Returns the arctangent of the quotient of its arguments."
},
"ceil": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/ceil",
"!doc": "Returns the smallest integer greater than or equal to a number."
},
"floor": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/floor",
"!doc": "Returns the largest integer less than or equal to a number."
},
"round": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/round",
"!doc": "Returns the value of a number rounded to the nearest integer."
},
"exp": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/exp",
"!doc": "Returns Ex, where x is the argument, and E is Euler's constant, the base of the natural logarithms."
},
"log": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/log",
"!doc": "Returns the natural logarithm (base E) of a number."
},
"sqrt": {
"!type": "fn(number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/sqrt",
"!doc": "Returns the square root of a number."
},
"pow": {
"!type": "fn(number, number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/pow",
"!doc": "Returns base to the exponent power, that is, baseexponent."
},
"max": {
"!type": "fn(number, number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/max",
"!doc": "Returns the largest of zero or more numbers."
},
"min": {
"!type": "fn(number, number) -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/min",
"!doc": "Returns the smallest of zero or more numbers."
},
"random": {
"!type": "fn() -> number",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math/random",
"!doc": "Returns a floating-point, pseudo-random number in the range [0, 1) that is, from 0 (inclusive) up to but not including 1 (exclusive), which you can then scale to your desired range."
},
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Math",
"!doc": "A built-in object that has properties and methods for mathematical constants and functions."
},
"JSON": {
"parse": {
"!type": "fn(json: string) -> ?",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/parse",
"!doc": "Parse a string as JSON, optionally transforming the value produced by parsing."
},
"stringify": {
"!type": "fn(value: ?) -> string",
"!url": "https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify",
"!doc": "Convert a value to JSON, optionally replacing values if a replacer function is specified, or optionally including only the specified properties if a replacer array is specified."
},
"!url": "https://developer.mozilla.org/en-US/docs/JSON",
"!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
DevToolsModules(
'browser.js',
'comment.js',
'condense.js',
'def.js',
'ecma5.js',
'infer.js',
'signal.js',
'tern.js',
)

View file

@ -1,51 +0,0 @@
(function(root, mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
return mod(exports);
if (typeof define == "function" && define.amd) // AMD
return define(["exports"], mod);
mod((root.tern || (root.tern = {})).signal = {}); // Plain browser env
})(this, function(exports) {
function on(type, f) {
var handlers = this._handlers || (this._handlers = Object.create(null));
(handlers[type] || (handlers[type] = [])).push(f);
}
function off(type, f) {
var arr = this._handlers && this._handlers[type];
if (arr) for (var i = 0; i < arr.length; ++i)
if (arr[i] == f) { arr.splice(i, 1); break; }
}
var noHandlers = []
function getHandlers(emitter, type) {
var arr = emitter._handlers && emitter._handlers[type];
return arr && arr.length ? arr.slice() : noHandlers
}
function signal(type, a1, a2, a3, a4) {
var arr = getHandlers(this, type)
for (var i = 0; i < arr.length; ++i) arr[i].call(this, a1, a2, a3, a4)
}
function signalReturnFirst(type, a1, a2, a3, a4) {
var arr = getHandlers(this, type)
for (var i = 0; i < arr.length; ++i) {
var result = arr[i].call(this, a1, a2, a3, a4)
if (result) return result
}
}
function hasHandler(type) {
var arr = this._handlers && this._handlers[type]
return arr && arr.length > 0 && arr
}
exports.mixin = function(obj) {
obj.on = on; obj.off = off;
obj.signal = signal;
obj.signalReturnFirst = signalReturnFirst;
obj.hasHandler = hasHandler;
return obj;
};
});

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
"use strict";
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");

View file

@ -1,26 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that tern autocompletions work.
*/
const tern = require("devtools/client/shared/sourceeditor/tern/tern");
const ecma5 = require("devtools/client/shared/sourceeditor/tern/ecma5");
function run_test() {
do_test_pending();
const server = new tern.Server({ defs: [ecma5] });
const code = "[].";
const query = { type: "completions", file: "test", end: code.length };
const files = [{ type: "full", name: "test", text: code }];
server.request({ query: query, files: files }, (error, response) => {
Assert.equal(error, null);
Assert.ok(!!response);
Assert.ok(Array.isArray(response.completions));
Assert.ok(response.completions.includes("concat"));
do_test_finished();
});
}

View file

@ -1,16 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Test that we can require tern.
*/
function run_test() {
const tern = require("devtools/client/shared/sourceeditor/tern/tern");
const ecma5 = require("devtools/client/shared/sourceeditor/tern/ecma5");
const browser = require("devtools/client/shared/sourceeditor/tern/browser");
Assert.ok(!!tern);
Assert.ok(!!ecma5);
Assert.ok(!!browser);
Assert.equal(typeof tern.Server, "function");
}

View file

@ -1,7 +0,0 @@
[DEFAULT]
tags = devtools
head = head_tern.js
firefox-appdir = browser
[test_autocompletion.js]
[test_import_tern.js]

View file

@ -29,7 +29,6 @@ support-files =
[browser_editor_autocomplete_basic.js]
[browser_editor_autocomplete_events.js]
[browser_editor_autocomplete_js.js]
[browser_editor_alt_b_f.js]
[browser_editor_basic.js]
[browser_editor_cursor.js]

View file

@ -20,24 +20,20 @@ async function test() {
function testJS(ed, win) {
ok(!ed.getOption("autocomplete"), "Autocompletion is not set");
ok(!win.tern, "Tern is not defined on the window");
ed.setMode(Editor.modes.js);
ed.setOption("autocomplete", true);
ok(ed.getOption("autocomplete"), "Autocompletion is set");
ok(win.tern, "Tern is defined on the window");
}
function testCSS(ed, win) {
ok(ed.getOption("autocomplete"), "Autocompletion is set");
ok(win.tern, "Tern is currently defined on the window");
ed.setMode(Editor.modes.css);
ed.setOption("autocomplete", true);
ok(ed.getOption("autocomplete"), "Autocompletion is still set");
ok(!win.tern, "Tern is no longer defined on the window");
}
function testPref(ed, win) {
@ -45,13 +41,11 @@ function testPref(ed, win) {
ed.setOption("autocomplete", true);
ok(ed.getOption("autocomplete"), "Autocompletion is set");
ok(win.tern, "Tern is defined on the window");
info("Preffing autocompletion off");
Services.prefs.setBoolPref(AUTOCOMPLETION_PREF, false);
ok(ed.getOption("autocomplete"), "Autocompletion is still set");
ok(!win.tern, "Tern is no longer defined on the window");
Services.prefs.clearUserPref(AUTOCOMPLETION_PREF);
}

View file

@ -1,41 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test to make sure that JS autocompletion is opening popups.
async function test() {
waitForExplicitFinish();
const { ed, win } = await setup();
const edWin = ed.container.contentWindow.wrappedJSObject;
await testJS(ed, edWin);
teardown(ed, win);
}
function testJS(ed, win) {
ok(!ed.getOption("autocomplete"), "Autocompletion is not set");
ok(!win.tern, "Tern is not defined on the window");
ed.setMode(Editor.modes.js);
ed.setOption("autocomplete", true);
ok(ed.getOption("autocomplete"), "Autocompletion is set");
ok(win.tern, "Tern is defined on the window");
ed.focus();
ed.setText("document.");
ed.setCursor({ line: 0, ch: 9 });
return new Promise(resolve => {
ed.on("before-suggest", () => {
info("before-suggest has been triggered");
EventUtils.synthesizeKey("VK_ESCAPE", {}, win);
resolve();
});
const autocompleteKey = Editor.keyFor("autocompletion", {
noaccel: true,
}).toUpperCase();
EventUtils.synthesizeKey("VK_" + autocompleteKey, { ctrlKey: true }, win);
});
}