├── .gitattributes
├── .gitignore
├── .jshintrc
├── .no-sublime-package
├── .tern-project
├── .travis.yml
├── AUTHORS
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bin
├── condense
├── tern
├── test
└── update_authors.sh
├── defs
├── browser.json
├── chai.json
├── ecmascript.json
├── jquery.json
├── react.json
└── underscore.json
├── doc
├── BACKERS.txt
├── Makefile
├── asciidoc.conf
├── demo
│ ├── demo.css
│ ├── demo.js
│ ├── index.html
│ ├── polyfill.js
│ └── underscore.js
├── docs.css
├── header.svg
├── logo.png
├── manual.html
└── manual.txt
├── emacs
├── tern-auto-complete.el
└── tern.el
├── index.html
├── lib
├── bootstrap.js
├── comment.js
├── condense.js
├── def.js
├── infer.js
├── signal.js
└── tern.js
├── package.json
├── plugin
├── angular.js
├── commonjs.js
├── complete_strings.js
├── doc_comment.js
├── es_modules.js
├── modules.js
├── node.js
├── node_resolve.js
├── requirejs.js
└── webpack.js
└── test
├── cases
├── angular
│ ├── config.js
│ ├── filters.js
│ └── main.js
├── angular_service.js
├── arguments.js
├── arithmetic_ops.js
├── array_holes.js
├── arrow.js
├── async-arrow.js
├── async.js
├── async_for_of.js
├── async_generator.js
├── autothis.js
├── bind.js
├── block_scope.js
├── blowup.js
├── browser.js
├── builtins.js
├── catch_error.js
├── cautiouspropagation.js
├── class.js
├── complete_strings.js
├── computedprop.js
├── contextcomplete.js
├── copyprops.js
├── ctorpattern.js
├── def_type_string.js
├── defineProperty.js
├── defs
│ ├── span.json
│ └── string.json
├── destructure.js
├── docstrings.js
├── effects.js
├── empty_overridden_prop.js
├── es6-features.js
├── es_modules
│ ├── blah.js
│ ├── class.js
│ ├── foo.js
│ ├── func.js
│ ├── main.js
│ ├── obj.js
│ └── reexp.js
├── extends.js
├── fetch.js
├── finddef.js
├── findref.js
├── fn_arguments.js
├── for_of.js
├── formdata.js
├── generator.js
├── generic_each.js
├── getter.js
├── global_this.js
├── hint-objlit.js
├── hint_browser.js
├── hint_ecma5.js
├── hint_simple.js
├── in_comment.js
├── indirect_class.js
├── infinite-expansion.js
├── jquery_event.js
├── jsdoc.js
├── map.js
├── merge.js
├── mixin.js
├── navigator.js
├── new_array.js
├── new_to_prototype.js
├── node
│ ├── binary.node
│ ├── dir
│ │ ├── index.js
│ │ └── lib
│ │ │ ├── other.js
│ │ │ └── relative.js
│ ├── exportfunc.js
│ ├── localfile.js
│ └── main.js
├── node_exports.js
├── node_modules
│ ├── mod1
│ │ ├── a.js
│ │ ├── dir1
│ │ │ └── index.js
│ │ ├── doc.js
│ │ ├── mainfile.js
│ │ ├── node_modules
│ │ │ └── subdep1
│ │ │ │ ├── package.json
│ │ │ │ └── subdep1.js
│ │ ├── package.json
│ │ ├── reassign_exports.js
│ │ ├── reassign_exports_to_required.js
│ │ └── secondfile.js
│ └── mymod.json
├── node_origin_paths.js
├── object-string-prop.js
├── object_create.js
├── objectlit.js
├── objnames.js
├── or_empty_array.js
├── order_of_definition.js
├── phantom_object.js
├── plus.js
├── promise.js
├── proto.js
├── protoname.js
├── replace_bogus_prop.js
├── requirejs
│ ├── bar.js
│ ├── baz.js
│ ├── foo.js
│ ├── func.js
│ ├── main.js
│ ├── module_exports.js
│ ├── named.js
│ ├── requireme.js
│ ├── simplifiedcommon.js
│ ├── subdir
│ │ └── zap.js
│ └── useexports.js
├── requirejs_config
│ └── main.js
├── set.js
├── simple.js
├── simple_generic.js
├── span_from_def.js
├── super.js
├── symbol.js
├── template.js
├── underscore.js
└── webpack
│ ├── component
│ └── foo.js
│ ├── main.js
│ ├── node_modules
│ ├── esnext
│ │ ├── index.js
│ │ └── package.json
│ ├── foo
│ │ ├── browser.js
│ │ ├── index.js
│ │ └── package.json
│ ├── modu
│ │ ├── index.js
│ │ └── package.json
│ └── xyz
│ │ ├── index.js
│ │ └── package.json
│ └── webpack.config.js
├── condense.js
├── condense
├── add_to_old.js
├── add_to_old.json
├── angular_simple.js
├── angular_simple.json
├── array.js
├── array.json
├── basic.js
├── basic.json
├── double_ref.js
├── double_ref.json
├── extend_foo.js
├── fn.js
├── fn.json
├── function_prop.js
├── function_prop.json
├── generic.js
├── generic.json
├── ignore_newer.js
├── ignore_newer.json
├── node_export_function_a.js
├── node_fn_export.js
├── node_fn_export.json
├── node_other_module_type_ref.js
├── node_other_module_type_ref.json
├── node_require_private.js
├── node_require_private.json
├── node_simple.js
├── node_simple.json
├── proto.js
├── proto.json
├── recursive.js
├── recursive.json
├── ref_in_type.js
├── ref_in_type.json
├── ref_to_old.js
├── ref_to_old.json
├── requirejs_const.js
├── requirejs_const.json
├── requirejs_dep.js
├── requirejs_dep.json
├── requirejs_empty_deps.js
├── requirejs_empty_deps.json
├── requirejs_primitive.js
├── requirejs_primitive.json
├── requirejs_setup.js
├── requirejs_setup.json
├── uniontype.js
└── uniontype.json
├── data
└── large.js
├── fragments.js
├── reload.js
├── runcases.js
├── timeout.js
└── util.js
/.gitattributes:
--------------------------------------------------------------------------------
1 | test/**/* text eol=lf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .tern-port
2 | /node_modules
3 | /misc
4 | *.elc
5 | *.pyc
6 |
7 | .DS_Store
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "sub" : true,
3 | "boss" : true,
4 | "expr" : true,
5 | "node" : true,
6 | "devel" : true,
7 | "curly" : false,
8 | "immed" : true,
9 | "noarg" : true,
10 | "undef" : true,
11 | "newcap" : true,
12 | "shadow" : true,
13 | "newcap" : false,
14 | "eqnull" : true,
15 | "jquery" : true,
16 | "eqeqeq" : false,
17 | "browser" : true,
18 | "latedef" : false,
19 | "supernew" : true,
20 | "laxcomma" : false,
21 | "laxbreak" : true,
22 | "lastsemic": true,
23 | "globals" : {"tern": true, "acorn": true, "define": true},
24 | "loopfunc" : true
25 | }
--------------------------------------------------------------------------------
/.no-sublime-package:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.tern-project:
--------------------------------------------------------------------------------
1 | {
2 | "libs": [
3 | ],
4 | "plugins": {
5 | "node": {},
6 | "complete_strings": {}
7 | }
8 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: node_js
4 |
5 | node_js:
6 | - 9
7 | - 8
8 | - 7
9 | - 6
10 |
11 | cache:
12 | directories:
13 | - node_modules
14 |
15 | install:
16 | - npm i -g npm@latest
17 | - npm install
18 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | List of Tern contributors. Updated before every release.
2 |
3 | A2ZH
4 | Adam Faulkner
5 | Adam Niederer
6 | Adrian Toncean
7 | AGhost-7
8 | Albertina Durante
9 | Alex Pinder
10 | Alex Saveliev
11 | Amila Welihinda
12 | Anders Thøgersen
13 | angelozerr
14 | Antonina Cherednichenko
15 | Ben Joldersma
16 | Ben McCormick
17 | berkin
18 | Boris Jonica
19 | Brian Frichette
20 | byronigoe
21 | CentricStorm
22 | chemzqm
23 | Claus Reinke
24 | Connor Osborn
25 | Curtis Windatt
26 | Damien Diederen
27 | Dani Hodovic
28 | Danny Su
29 | Dewdrops
30 | dloverin
31 | Dmitry Gutov
32 | eidheim
33 | Eloy Toro
34 | Erik Tierney
35 | Fabian Zeindl
36 | Forbes Lindesay
37 | Francisc Romano
38 | Francis Murillo
39 | Hans Huebner
40 | Hiroaki Otsu
41 | Iku Iwasa
42 | impinball
43 | i-p
44 | itai
45 | Jackson Ray Hamilton
46 | J David Smith
47 | Jeffrey Fisher
48 | Jeff Stern
49 | Jonathan Persson
50 | Josh Giles
51 | jzhang
52 | katspaugh
53 | Kim Se-won
54 | Kyle P Davis
55 | liuyujun
56 | Marcel Gerber
57 | Marcello Bastea-Forte
58 | Marijn Haverbeke
59 | Matt
60 | Matteo Landi
61 | Matthias Dahl
62 | Matthis LEMAITRE--COSQUER
63 | Max Schaefer
64 | MetaMemoryT
65 | Michael Russell
66 | Michał Grzejszczak
67 | Miguel Castillo
68 | Mihai Bazon
69 | Mike Rennie
70 | Mikko Rantanen
71 | Miroslav Bajtoš
72 | Mounir Lamouri
73 | Nallamalli Venkata Sai Krishna
74 | Nate Eagleson
75 | Neha Modi
76 | Nick Malaguti
77 | Nicolas Petton
78 | Nico Weber
79 | Nikolaj Kappler
80 | Olivier Ligot
81 | Ossi Herrala
82 | othree
83 | Paris Kasidiaris
84 | partizan
85 | Paul Bakker
86 | Paul Verest
87 | Peter Elmers
88 | Peter Farland
89 | Piotr Tomiak
90 | Pok-Pok
91 | Quinn Slack
92 | Ralf Kistner
93 | Randy Edmunds
94 | Renato F
95 | Renato Ferreira
96 | Reuben Thomas
97 | Ryan Stewart
98 | SAKURAI Masashi
99 | Sean Usick
100 | Sergey Chikuyonok
101 | Sérgio Ramos
102 | sevin7676
103 | Se-Won Kim
104 | sharils
105 | Sindre Sorhus
106 | Slava Kim
107 | Stephan Seidt
108 | Steve Purcell
109 | stoskov
110 | tijsmallaerts
111 | Tim M. Madsen
112 | Timothy Gu
113 | Tommy Troy Lin
114 | Trey Thomas
115 | vheon
116 | Vincent Woo
117 | xd1le
118 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Tern
2 |
3 | ## Submitting bug reports
4 |
5 | The preferred way to report bugs is to use the [GitHub issue
6 | tracker](http://github.com/ternjs/tern/issues). Please put some
7 | thought and energy into your report, to make it easy for us to help
8 | you.
9 |
10 | - Describe very precisely what went wrong. "X is broken" is not a good bug
11 | report. What did you expect to happen? What happened instead?
12 |
13 | - Provide a way for the maintainer to reproduce the problem you are
14 | seeing. That sometimes means waiting for a problem to occur a second
15 | time, and experimenting to see exactly which circumstances trigger
16 | the problem. We can rarely fix bugs that we can not reproduce.
17 |
18 | - Reduce your instructions for reproducing the bug as much as
19 | possible. The more irrelevant pieces (code, steps) are included, the
20 | more time we'll have to waste going through them.
21 |
22 | - Mention which exact version (release number or, if you got the code
23 | from git, revision hash) of Tern you are using. Include your project
24 | configuration if there is any chance of it being relevant.
25 |
26 | - Be civil. The project is maintained by volunteers who do not owe you
27 | anything. Reports with an indignant or belligerent tone tend to be
28 | moved to the bottom of the pile.
29 |
30 | ## Contributing code
31 |
32 | The preferred way to contribute code is through GitHub pull requests.
33 |
34 | If you plan to do something major, please discuss it on the [mailing
35 | list](https://groups.google.com/forum/?fromgroups#!forum/tern-dev)
36 | first, to avoid wasting time on something that will not be merged.
37 |
38 | Follow the project's general coding style. Patches that randomly
39 | change code to your preferred coding style or reorganize code for
40 | subjective reasons will not be accepted.
41 |
42 | By contributing code to Tern you
43 |
44 | - agree to license the contributed code under Tern's [MIT
45 | license](http://ternjs.net/LICENSE).
46 |
47 | - confirm that you have the right to contribute and license the code
48 | in question. (Either you hold all rights on the code, or the rights
49 | holder has explicitly granted the right to use it like this,
50 | through a compatible open source license or through a direct
51 | agreement with you.)
52 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2013 by Marijn Haverbeke and others
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tern
2 |
3 | [](http://travis-ci.org/ternjs/tern)
4 | [](https://www.npmjs.org/package/tern)
5 |
6 |
7 | This is [Tern][1]. Tern is a stand-alone, editor-independent
8 | JavaScript analyzer that can be used to improve the JavaScript
9 | integration of existing editors.
10 |
11 | Thanks to a group of generous [crowd funders][2], Tern is open-source
12 | software, under an MIT license.
13 |
14 | There are currently plugins available for [Emacs][emacs] (and Emacs
15 | [company-mode][cmode]), [Vim][vim], [Sublime Text][st], [Eclipse (and general Java API)][ec],
16 | [Light Table][lt], [Atom][atom], [TextMate][tm] and [gedit][gedit], and built-in support in
17 | [Brackets][brackets], [Edge Code][edge_code], [CodeLite](http://codelite.org/),
18 | [vy](https://github.com/iogf/vy), and [SourceLair][sourcelair].
19 |
20 | For further documentation, see the [project page][1] and the
21 | [manual][3]. To report issues, use the
22 | [issue tracker](https://github.com/ternjs/tern/issues).
23 |
24 | [1]: http://ternjs.net
25 | [2]: http://www.indiegogo.com/projects/tern-intelligent-javascript-editing
26 | [3]: http://ternjs.net/doc/manual.html
27 |
28 | [emacs]: http://ternjs.net/doc/manual.html#emacs
29 | [ec]: https://github.com/angelozerr/tern.java
30 | [vim]: https://github.com/ternjs/tern_for_vim
31 | [st]: https://github.com/ternjs/tern_for_sublime
32 | [lt]: https://github.com/mortalapeman/LT-TernJS
33 | [atom]: https://atom.io/packages/atom-ternjs
34 | [gedit]: https://github.com/Swatinem/tern_for_gedit
35 | [brackets]: http://brackets.io
36 | [edge_code]: http://html.adobe.com/edge/code
37 | [cmode]: https://github.com/proofit404/company-tern
38 | [tm]: https://github.com/fab1an/JavaScript-Tern-Completion.tmbundle
39 | [sourcelair]: https://www.sourcelair.com
40 |
--------------------------------------------------------------------------------
/bin/condense:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var tern = require("../lib/tern"), condense = require("../lib/condense");
4 | var path = require("path"), fs = require("fs");
5 | require("../plugin/doc_comment");
6 |
7 | var localDir = process.cwd(), ourDir = path.resolve(__dirname, "..");
8 | var spans = true;
9 |
10 | function usage(exit) {
11 | console.error("usage: " + process.argv[1] + " [--name name] [--plugin name]* [--def name]* [+extrafile.js]* [file.js]+");
12 | if (exit != null) process.exit(exit);
13 | }
14 |
15 | function findFile(file, where, ext) {
16 | if (file.slice(file.length - ext.length) != ext) file += ext;
17 | var local = path.resolve(localDir, file);
18 | if (fs.existsSync(local)) return local;
19 | var our = path.resolve(path.resolve(ourDir, where), file);
20 | if (fs.existsSync(our)) return our;
21 | }
22 |
23 | var defs = [], plugins = {doc_comment: {}}, files = [], name;
24 |
25 | function loadDef(name) {
26 | var found = findFile(name, "defs", ".json");
27 | if (!found) {
28 | console.error("Could not find def file " + name);
29 | process.exit(1);
30 | }
31 | defs.push(JSON.parse(fs.readFileSync(found, "utf8")));
32 | }
33 |
34 | loadDef("ecmascript");
35 |
36 | function loadPlugin(name, val) {
37 | var found = findFile(name, "plugin", ".js");
38 | if (!found) {
39 | try {
40 | found = require.resolve("tern-" + name);
41 | } catch (e) {
42 | console.error("Could not find plugin " + name);
43 | process.exit(1);
44 | }
45 | }
46 | var mod = require(found);
47 | if (mod.hasOwnProperty("initialize")) mod.initialize(ourDir);
48 | plugins[path.basename(name, ".js")] = val;
49 | }
50 |
51 | for (var i = 2, len = process.argv.length; i < len; ++i) {
52 | var cur = process.argv[i];
53 | if (cur == "--plugin" && i < len - 1) {
54 | var plugin = process.argv[++i], eq = plugin.indexOf("=");
55 | if (eq > -1)
56 | loadPlugin(plugin.slice(0, eq), JSON.parse(plugin.slice(eq + 1)));
57 | else
58 | loadPlugin(plugin, {});
59 | } else if (cur == "--def" && i < len - 1) {
60 | loadDef(process.argv[++i]);
61 | } else if (cur == "--name" && i < len - 1) {
62 | name = process.argv[++i];
63 | } else if (cur == "--no-spans") {
64 | spans = false;
65 | } else if (cur.charAt(0) == "-") {
66 | usage(1);
67 | } else {
68 | files.push(cur);
69 | }
70 | }
71 |
72 | var server = new tern.Server({
73 | getFile: function(file) { return fs.readFileSync(path.resolve(localDir, file), "utf8"); },
74 | defs: defs,
75 | plugins: plugins,
76 | debug: true,
77 | projectDir: localDir
78 | });
79 |
80 | var origins = [];
81 | for (var i = 0; i < files.length; ++i) {
82 | var file = files[i];
83 | if (file.charAt(0) == "+") {
84 | file = file.slice(1);
85 | } else {
86 | origins.push(file);
87 | if (!name) name = file;
88 | }
89 | if (!fs.existsSync(file)) {
90 | console.error("File " + file + " does not exist");
91 | process.exit(1);
92 | }
93 | server.addFile(file, fs.readFileSync(file, "utf8"));
94 | }
95 |
96 | if (!origins.length) usage(1);
97 |
98 | server.flush(function(err) {
99 | if (err) throw err;
100 | console.log(JSON.stringify(condense.condense(origins, name, {spans: spans}), null, 2));
101 | });
102 |
--------------------------------------------------------------------------------
/bin/tern:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | // HTTP server for desktop editors
4 |
5 | // Starts a Tern server and wraps it in an HTTP wrapper
6 | // so that editor plug-ins can talk to it.
7 |
8 | var bootstrapServer = require('../lib/bootstrap');
9 | var fs = require("fs"), path = require("path"), url = require("url");
10 |
11 | var portFileName = ".tern-port";
12 | var maxIdleTime = 6e4 * 5; // Shut down after five minutes of inactivity
13 |
14 | var persistent = process.argv.indexOf("--persistent") > -1;
15 | var stripCRs = process.argv.indexOf("--strip-crs") > -1;
16 | var disableLoadingLocal = process.argv.indexOf("--disable-loading-local") > -1;
17 | var verbose = process.argv.indexOf("--verbose") > -1;
18 | var debug = verbose || process.argv.indexOf("--debug") > -1;
19 | var noPortFile = process.argv.indexOf("--no-port-file") > -1;
20 | var host = "127.0.0.1";
21 | var hostArg = process.argv.indexOf("--host");
22 | if (hostArg > -1) {
23 | host = process.argv[hostArg + 1];
24 | if (host == "null" || host == "any") host = null;
25 | }
26 | var port = 0;
27 | var portArg = process.argv.indexOf("--port");
28 | if (portArg > -1) {
29 | port = Number(process.argv[portArg + 1]);
30 | if (isNaN(port)) port = 0;
31 | }
32 | var ignoreStdin = process.argv.indexOf("--ignore-stdin") > -1;
33 |
34 | var httpServer = require("http").createServer(function(req, resp) {
35 | clearTimeout(shutdown);
36 | shutdown = setTimeout(doShutdown, maxIdleTime);
37 |
38 | var target = url.parse(req.url, true);
39 | if (target.pathname == "/ping") return respondSimple(resp, 200, "pong");
40 | if (target.pathname != "/") return respondSimple(resp, 404, "No service at " + target.pathname);
41 |
42 | if (req.method == "POST") {
43 | var body = "";
44 | req.on("data", function (data) { body += data; });
45 | req.on("end", function() { respond(resp, body); });
46 | } else if (req.method == "GET") {
47 | if (target.query.doc) respond(resp, target.query.doc);
48 | else respondSimple(resp, 400, "Missing query document");
49 | }
50 | });
51 |
52 | var serverConfig = {
53 | disableLoadingLocal: disableLoadingLocal,
54 | tern: {
55 | stripCRs: stripCRs,
56 | debug: debug,
57 | parent: { httpServer: httpServer }
58 | }
59 | };
60 | var server = bootstrapServer(serverConfig);
61 |
62 | function doShutdown() {
63 | if (persistent) return;
64 | console.log("Was idle for " + Math.floor(maxIdleTime / 6e4) + " minutes. Shutting down.");
65 | process.exit();
66 | }
67 |
68 | var shutdown = setTimeout(doShutdown, maxIdleTime);
69 |
70 | if (!ignoreStdin) {
71 | process.stdin.on("end", function() {
72 | console.log("stdin pipe closed, killing tern");
73 | process.exit();
74 | });
75 | process.stdin.resume();
76 | }
77 |
78 | httpServer.listen(port, host, function() {
79 | var port = httpServer.address().port;
80 | if (!noPortFile) {
81 | var portFile = path.resolve(server.projectDir, portFileName);
82 | fs.writeFileSync(portFile, String(port), "utf8");
83 | process.on("exit", function() {
84 | try {
85 | var cur = Number(fs.readFileSync(portFile, "utf8"));
86 | if (cur == port) fs.unlinkSync(portFile);
87 | } catch(e) {}
88 | });
89 | }
90 | process.on("SIGINT", function() {
91 | console.log("SIGINT trapped, killing tern");
92 | process.exit();
93 | });
94 | process.on("SIGTERM", function() {
95 | console.log("SIGTERM trapped, killing tern");
96 | process.exit();
97 | });
98 | console.log("Listening on port " + port);
99 | });
100 |
101 | function respondSimple(resp, status, text) {
102 | resp.writeHead(status, {"content-type": "text/plain; charset=utf-8"});
103 | resp.end(text);
104 | if (verbose) console.log("Response: " + status + " " + text);
105 | }
106 |
107 | function respond(resp, doc) {
108 | try { var doc = JSON.parse(doc); }
109 | catch(e) { return respondSimple(resp, 400, "JSON parse error: " + e.message); }
110 | if (verbose) console.log("Request: " + JSON.stringify(doc, null, 2));
111 |
112 | server.request(doc, function(err, data) {
113 | if (err) return respondSimple(resp, 400, String(err));
114 | resp.writeHead(200, {"content-type": "application/json; charset=utf-8"});
115 | if (verbose) console.log("Response: " + JSON.stringify(data, null, 2) + "\n");
116 | resp.end(JSON.stringify(data));
117 | });
118 | }
119 |
--------------------------------------------------------------------------------
/bin/test:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | var filter = process.argv[2];
4 |
5 | require("../test/runcases").runTests(filter);
6 | require("../test/fragments").runTests(filter);
7 | require("../test/condense").runTests(filter);
8 | require("../test/timeout").runTests(filter);
9 | require("../test/reload").runTests(filter);
10 |
11 | process.exit(require("../test/util").hasFailed());
12 |
--------------------------------------------------------------------------------
/bin/update_authors.sh:
--------------------------------------------------------------------------------
1 | # Combine existing list of authors with everyone known in git, sort, add header.
2 | tail --lines=+3 AUTHORS > AUTHORS.tmp
3 | git log --format='%aN' | grep -v 'Sérgio Ramos\|othree_kao\|Angelo$' >> AUTHORS.tmp
4 | echo -e "List of Tern contributors. Updated before every release.\n" > AUTHORS
5 | sort -u AUTHORS.tmp >> AUTHORS
6 | rm -f AUTHORS.tmp
7 |
--------------------------------------------------------------------------------
/defs/react.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "react",
3 | "!define": {
4 | "Component": {
5 | "!doc": "Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.",
6 | "!url": "https://reactjs.org/docs/components-and-props.html",
7 | "defaultProps": {
8 | "!type": "?",
9 | "!doc": "defaultProps can be defined as a property on the component class itself, to set the default props for the class.",
10 | "!url": "https://facebook.github.io/react/docs/react-component.html#defaultprops"
11 | },
12 | "displayName": {
13 | "!type": "string",
14 | "!doc": "The displayName string is used in debugging messages.",
15 | "!url": "https://facebook.github.io/react/docs/react-component.html#displayname"
16 | },
17 | "propTypes": {
18 | "!type": "PropTypes",
19 | "!doc": "To run typechecking on the props for a component, you can assign the special propTypes property.",
20 | "!url": "https://facebook.github.io/react/docs/typechecking-with-proptypes.html"
21 | },
22 | "prototype": {
23 | "props": "?",
24 | "state": "?",
25 | "setState": {
26 | "!type": "fn(updater: ?, callback?: fn())",
27 | "!doc": "setState() enqueues changes to the component state and tells React that this component and its children need to be re-rendered with the updated state.",
28 | "!url": "https://facebook.github.io/react/docs/react-component.html#setstate"
29 | },
30 | "forceUpdate": {
31 | "!type": "fn(callback: fn())",
32 | "!doc": "By default, when your component's state or props change, your component will re-render. If your render() method depends on some other data, you can tell React that the component needs re-rendering by calling forceUpdate().",
33 | "!url": "https://facebook.github.io/react/docs/react-component.html#forceupdate"
34 | }
35 | }
36 | },
37 | "ReactElement": {
38 | "!doc": "Elements are the smallest building blocks of React apps.",
39 | "!url": "https://reactjs.org/docs/rendering-elements.html"
40 | },
41 | "ref": {
42 | "!doc": "Refs provide a way to access DOM nodes or React elements created in the render method.",
43 | "!url": "https://reactjs.org/docs/refs-and-the-dom.html",
44 | "current": "node"
45 | },
46 | "PropTypes": {
47 | "!doc": "Runtime type checking for React props and similar objects.",
48 | "!url": "https://github.com/facebook/prop-types/",
49 | "array": {
50 | "!type": "PropType",
51 | "!doc": "You can declare that a prop is a specific JS primitive."
52 | },
53 | "bool": {
54 | "!type": "PropType",
55 | "!doc": "You can declare that a prop is a specific JS primitive."
56 | },
57 | "func": {
58 | "!type": "PropType",
59 | "!doc": "You can declare that a prop is a specific JS primitive."
60 | },
61 | "number": {
62 | "!type": "PropType",
63 | "!doc": "You can declare that a prop is a specific JS primitive."
64 | },
65 | "object": {
66 | "!type": "PropType",
67 | "!doc": "You can declare that a prop is a specific JS primitive."
68 | },
69 | "string": {
70 | "!type": "PropType",
71 | "!doc": "You can declare that a prop is a specific JS primitive."
72 | },
73 | "symbol": {
74 | "!type": "PropType",
75 | "!doc": "You can declare that a prop is a specific JS primitive."
76 | },
77 | "node": {
78 | "!type": "PropType",
79 | "!doc": "Anything that can be rendered: numbers, strings, elements or an array (or fragment) containing these types."
80 | },
81 | "element": {
82 | "!type": "PropType",
83 | "!doc": "A React element."
84 | },
85 | "instanceOf": {
86 | "!type": "fn(class: fn()) -> PropType",
87 | "!doc": "You can also declare that a prop is an instance of a class. This uses JS's instanceof operator."
88 | },
89 | "oneOf": {
90 | "!type": "fn([?]) -> PropType",
91 | "!doc": "You can ensure that your prop is limited to specific values by treating it as an enum."
92 | },
93 | "oneOfType": {
94 | "!type": "fn([PropType]) -> PropType",
95 | "!doc": "An object that could be one of many types"
96 | },
97 | "arrayOf": {
98 | "!type": "fn(propType: PropType) -> PropType",
99 | "!doc": "An array of a certain type"
100 | },
101 | "objectOf": {
102 | "!type": "fn(propType: PropType) -> PropType",
103 | "!doc": "An object with property values of a certain type"
104 | },
105 | "shape": {
106 | "!type": "fn(propTypes: PropTypes) -> PropType",
107 | "!doc": "An object taking on a particular shape"
108 | },
109 | "any": {
110 | "!type": "PropType",
111 | "!doc": "A value of any data type"
112 | }
113 | },
114 | "PropType": {
115 | "isRequired": {
116 | "!doc": "You can chain any of the above with `isRequired` to make sure a warning is shown if the prop isn't provided"
117 | }
118 | }
119 | },
120 | "PropTypes": "PropTypes",
121 | "React": {
122 | "!doc": "React is the entry point to the React library.",
123 | "!url": "https://reactjs.org/docs/react-api.html",
124 | "Component": {
125 | "!type": "fn() -> Component",
126 | "!doc": "React.Component is the base class for React components when they are defined using ES6 classes",
127 | "!url": "https://reactjs.org/docs/react-api.html#reactcomponent",
128 | "prototype": "Component"
129 | },
130 | "PureComponent": {
131 | "!type": "fn() -> Component",
132 | "!doc": "React.PureComponent is similar to React.Component. The difference between them is that React.Component doesn’t implement shouldComponentUpdate(), but React.PureComponent implements it with a shallow prop and state comparison.",
133 | "!url": "https://reactjs.org/docs/react-api.html#reactpurecomponent",
134 | "prototype": "Component"
135 | },
136 | "memo": {
137 | "!type": "Component",
138 | "!doc": "React.memo is a higher order component. It’s similar to React.PureComponent but for function components instead of classes.",
139 | "!url": "https://reactjs.org/docs/react-api.html#reactmemo"
140 | },
141 | "createElement": {
142 | "!type": "fn(element: ReactElement, props: [?], children: [?]) -> ReactElement",
143 | "!doc": "Create and return a new React element of the given type.",
144 | "!url": "https://reactjs.org/docs/react-api.html#createelement"
145 | },
146 | "cloneElement": {
147 | "!type": "fn(element: ReactElement, props: [?], children: [?]) -> ReactElement",
148 | "!doc": "Clone and return a new React element using element as the starting point.",
149 | "!url": "https://reactjs.org/docs/react-api.html#cloneelement"
150 | },
151 | "createFactory": {
152 | "!type": "fn(type: string|Component|React.Fragment) -> fn() -> ReactElement",
153 | "!doc": "",
154 | "!url": "https://reactjs.org/docs/react-api.html#createfactory"
155 | },
156 | "isValidElement": {
157 | "!type": "fn(object: ?) -> bool",
158 | "!doc": "Verifies the object is a React element. Returns true or false.",
159 | "!url": "https://reactjs.org/docs/react-api.html#isvalidelement"
160 | },
161 | "Children": {
162 | "map": {
163 | "!type": "fn(children: ?, fn()) -> [?]",
164 | "!doc": "Invokes a function on every immediate child contained within children with this set to thisArg.",
165 | "!url": "https://reactjs.org/docs/react-api.html#reactchildrenmap"
166 | },
167 | "forEach": {
168 | "!type": "fn(children: ?, fn())",
169 | "!doc": "Like React.Children.map() but does not return an array.",
170 | "!url": "https://reactjs.org/docs/react-api.html#reactchildrenforeach"
171 | },
172 | "count": {
173 | "!type": "fn(?) -> number",
174 | "!doc": "Returns the total number of components in children, equal to the number of times that a callback passed to map or forEach would be invoked.",
175 | "!url": "https://reactjs.org/docs/react-api.html#reactchildrencount"
176 | },
177 | "only": {
178 | "!type": "fn(?) -> Component",
179 | "!doc": "Verifies that children has only one child (a React element) and returns it. Otherwise this method throws an error.",
180 | "!url": "https://reactjs.org/docs/react-api.html#reactchildrenonly"
181 | },
182 | "toArray": {
183 | "!type": "fn(?) -> [Component]",
184 | "!doc": "Returns the children opaque data structure as a flat array with keys assigned to each child.",
185 | "!url": "https://reactjs.org/docs/react-api.html#reactchildrentoarray"
186 | }
187 | },
188 | "Fragment": {
189 | "!type": "Component",
190 | "!doc": "The React.Fragment component lets you return multiple elements in a render() method without creating an additional DOM element",
191 | "!url": "https://reactjs.org/docs/react-api.html#reactfragment"
192 | },
193 | "createRef": {
194 | "!type": "fn() -> ref",
195 | "!doc": "Refs are created using React.createRef() and attached to React elements via the ref attribute.",
196 | "!url": "https://reactjs.org/docs/refs-and-the-dom.html#creating-refs"
197 | },
198 | "forwardRef": {
199 | "!type": "fn(render: fn()) -> Component",
200 | "!doc": "Ref forwarding is a technique for automatically passing a ref through a component to one of its children.",
201 | "!url": "https://reactjs.org/docs/forwarding-refs.html"
202 | }
203 | },
204 | "ReactDOM": {
205 | "!doc": "The react-dom package provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to.",
206 | "!url": "https://reactjs.org/docs/react-dom.html",
207 | "render": {
208 | "!type": "fn(element: ReactElement, container: Element, callback?: fn()) -> !0",
209 | "!doc": "Render a React element into the DOM in the supplied container and return a reference to the component (or returns null for stateless components).",
210 | "!url": "https://facebook.github.io/react/docs/react-dom.html#render"
211 | },
212 | "hydrate": {
213 | "!type": "fn(element: ReactElement, container: Element, callback?: fn()) -> !0",
214 | "!doc": "Same as render(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer.",
215 | "!url": "https://reactjs.org/docs/react-dom.html#hydrate"
216 | },
217 | "unmountComponentAtNode": {
218 | "!type": "fn(container: Element) -> bool",
219 | "!doc": "Remove a mounted React component from the DOM and clean up its event handlers and state.",
220 | "!url": "https://facebook.github.io/react/docs/react-dom.html#unmountcomponentatnode"
221 | },
222 | "findDOMNode": {
223 | "!type": "fn(component: ReactElement) -> Element",
224 | "!doc": "If this component has been mounted into the DOM, this returns the corresponding native browser DOM element.",
225 | "!url": "https://facebook.github.io/react/docs/react-dom.html#finddomnode"
226 | },
227 | "createPortal": {
228 | "!type": "fn(component: ReactElement, container: Element) -> ReactElement",
229 | "!doc": "Creates a portal. Portals provide a way to render children into a DOM node that exists outside the hierarchy of the DOM component.",
230 | "!url": "https://reactjs.org/docs/portals.html"
231 | }
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/doc/BACKERS.txt:
--------------------------------------------------------------------------------
1 | Backers of the donation drive that made Tern open source
2 | See http://www.indiegogo.com/projects/tern-intelligent-javascript-editing
3 |
4 | Super backers:
5 |
6 | Telerik
7 | Karl Guertin
8 | Peter Lubbers
9 | Remy Sharp
10 | Anton Kovalyov
11 | Meryn Stol
12 | Rahul Choudhury
13 | Jake Verbaten
14 | Sébastien Gruhier
15 | Tim Branyen
16 |
17 | Further backers:
18 |
19 | Christophe Porteneuve
20 | James Morrin
21 | Marko Mikulicic
22 | Morgan Roderick
23 | Paul Irish
24 | wesen
25 | Aron Woost
26 | Brandon Frohs
27 | Dan Rogers
28 | Jan Krems
29 | Jörn Zaefferer
30 | Karl Forshaw
31 | Matt Claypotch
32 | Miguel Castillo
33 | Mihai Bazon
34 | patrick.wolf
35 | Rebecca Murphey
36 | Scott Sauyet
37 | Todd Wolfson
38 | Erik Söhnel
39 | Matt Pass
40 | Paul Grock
41 | Damian Soto
42 | Fayolle
43 | Pierre Spring
44 | Douglas Soares de Andrade
45 | egonelbre
46 | Gavin Suntop
47 | ivan4th
48 | Matt Field
49 | Tiffany Conroy
50 | Markus Messner-Chaney
51 | fronx
52 | A/C Luis Cardoso FeedZai S.A.
53 | aaron bieber
54 | Aaron Toth
55 | Adrian Christopher Schaedle
56 | Aijaz Mohammad
57 | Alberto Zaccagni
58 | Alex Sexton
59 | Alexandre Gaudencio
60 | Amrit Sundar Tuladhar
61 | Andreas Köberle
62 | Andrey Okonechnikov
63 | Andrius Kazdailevicius
64 | Antons Jakimovs
65 | Antranig Basman
66 | aowerb
67 | Arnout Kazemier
68 | Artur Carvalho
69 | Asbjørn Andersen
70 | Balázs Galambosi
71 | Baptiste Millou
72 | Bastiaan Rasing
73 | Ben Marvell
74 | Benoît Zugmeyer
75 | Björn Günzel
76 | Brad Dougherty
77 | Brandon Satrom
78 | Brian Brennan
79 | Brian Frichette
80 | bruce.mitchener
81 | Byron Darlison
82 | Chris Engebretson
83 | Christoffer Björkskog
84 | Christoph Schwienheer, bei Zierock
85 | Christopher Wyllie
86 | Codevise Solutions / Vangelis Tsoumenis
87 | Cristian Carlesso
88 | Cuong Vo
89 | Damien Klinnert
90 | Dan Reeves
91 | Dane Summers
92 | Daniel Kloosterman
93 | Daniel Wippermann
94 | Darren Waddell
95 | Daryl Koopersmith
96 | David Håsäther
97 | David JENNI
98 | David Sargeant
99 | David White
100 | Dethe Elza
101 | Dirk Ginader
102 | Dmitri Molchanenko
103 | Doc No
104 | Dominique Poulain
105 | Drew Miller
106 | Drew Neil
107 | Edd Hannay
108 | edouard duplessis
109 | Eike Send
110 | Felix Raab
111 | Ferdinand Salis-Samaden
112 | Filip Noetzel
113 | Frederick Ostrander
114 | Fronx Wurmus
115 | Gleb Mazovetskiy
116 | Gregers Rygg
117 | Hans Christian Reinl
118 | Hans Hübner
119 | Henrik vendelbo
120 | Henry Allen-Tilford
121 | Herculano Campos
122 | Hieu Nguyen
123 | holmlundlists
124 | Jack Franklin
125 | Jan Lehnardt
126 | Jan Löfberg
127 | Jans Aasman
128 | Jason LeMoine
129 | Jendrik Johannes
130 | jeroen14
131 | Jim Tittsler
132 | Joel M Hooks
133 | John Pallister
134 | Jonas Coch
135 | Jonathan Smart
136 | Joshua Kalis
137 | José María Balsas
138 | Julian Wachholz
139 | Justin Lowery
140 | Jyri Tuulos
141 | Karl J Smith
142 | Karl Vestin
143 | Kasper Fabæch Brandt
144 | Kevin Vlahos
145 | Marcell Mars
146 | Konstantin Käfer
147 | Kurt MacDonald
148 | Kyle Barrow
149 | Kyle Powers
150 | Lajos Koszti
151 | Laurie Kemmerer
152 | Loïc Moriamé
153 | Lukas F. Hartmann
154 | Luke Arduini
155 | Luke Karrys
156 | Luís Almeida
157 | Maciej Małecki
158 | Maksim Lin
159 | Marcin Wosinek
160 | Marco Rogers
161 | Marius Gundersen
162 | Martin Hansen
163 | Martin Moellenbeck
164 | Mat Brennan
165 | Matt Smillie
166 | Matthew Buscemi
167 | Matthew L Daniel
168 | Maurizio Mangione
169 | Max F. Albrecht
170 | Michael Goulbourn
171 | Michael Kessler
172 | Michael Lehenbauer
173 | Michael Russell
174 | Michael Zehrer
175 | Mikael Abrahamsson
176 | Mikko Ohtamaa
177 | Jonathan Puckey
178 | Niall O'Higgins
179 | Nicholas Niemeir
180 | Nicky B Hajal
181 | Niclas Hoyer
182 | Niklas Lindgren
183 | Olav Cleemann
184 | Oskar Schöldström
185 | Paolo Negri
186 | Patrick Arminio
187 | Patrik Henningsson
188 | Paul Conroy
189 | Paul Dijou
190 | Paul Young
191 | Peeter Tomberg
192 | Per Ejeklint
193 | Per Thulin
194 | Peter Wong
195 | Phillip Strong
196 | pjschaffner
197 | Raphael LANG
198 | Ray Cohen
199 | Richard Powell
200 | Rick Richardson
201 | Robert Oroszi
202 | Robin Brandt
203 | Ryan Morlok
204 | Ryan Wachtl
205 | Sveinung Røsaker
206 | Salvatore Formisano
207 | Scott White
208 | Seth House
209 | Simon Cossar
210 | Simon Goumaz
211 | Simon Jockers
212 | Stefan Gojan
213 | Stefan Hayden
214 | Stefan Kienzle
215 | Stephan Hoyer
216 | steve heron
217 | tape.io GmbH / Sascha Reuter
218 | Thanasis Polychronakis
219 | Thomas Bassetto
220 | Thomas Roger
221 | Tiago Rodrigues
222 | Tobias Kaatz
223 | Tom MacWright
224 | Tomasz Stryjewski
225 | Tommi Laine
226 | Tony Atkins
227 | Trey Griffith
228 | Vernon Kesner
229 | Victor Nguyen
230 | Vitaliy Meshchaninov
231 | Wolfram Twelker
232 | Zachary King
233 | Zaki Manian
234 | Ziga Ham
235 | Øystein Kjærnet
236 | 范致宣
237 | aritter
238 | David Flanagan
239 | Klemen Slavič
240 | Leichnig Loyce
241 | assaf3
242 | hebrox
243 | Kasra Kyanzadeh
244 | Pauld Aoust
245 | Roland Warmerdam
246 | Thomas Gorny
247 | Thomas Greiner
248 | Anders Madsen
249 | ceejceej
250 | Curist Chang
251 | Danny Coates
252 | David Owens
253 | dinalamdany
254 | dsmlover
255 | ebraun1
256 | Eugen Tudorancea
257 | Frode Nilsen
258 | glen15
259 | Irakli Nadareishvili
260 | Jack Ellis
261 | Jon Gjengset
262 | Michiel van Oosten
263 | mwsherman
264 | ncoder2000
265 | oogatta
266 | owz534
267 | rekurzija
268 | Rémi Gérard-Marchant
269 | rvagg
270 | shikakaa
271 | sressler1
272 | Stephan Seidt
273 | Tristen Brown
274 | Volodymyr Prokopyuk
275 | wbinnssmith
276 | Austin Montoya
277 | andr1
278 | Andrew Jones
279 | Bogdan Durla
280 | botequilha
281 | boyerchen
282 | brauer1
283 | Dmitry Semenov
284 | Dominik Rask
285 | eliasgs
286 | Hayden Chambers
287 | hugomallet06
288 | ithkuil
289 | jacek3
290 | jfromaniello
291 | Jiri Zuna
292 | johannes20
293 | Kyle Hardgrave
294 | larry8
295 | Lorenz Anmey
296 | Martin Hečko
297 | Max Shishkin
298 | Michi-Mueller
299 | Oliver Jash
300 | Gobin Goos
301 | Bob McBride
302 | roriz87
303 | RRTimmerman
304 | Sascha Greiff
305 | Sbastien Lebel
306 | Serkan Yersen
307 | Sindre Sorhus
308 | steve228uk
309 | Thomas Bartels
310 | Thomas Ruoff
311 | twilightfeel
312 | Wil Moore
313 | Xavier Seignard
314 | Cyrielvant End
315 | Tom Greuter
316 | Andrew Blackshaw
317 | Ben
318 | bitomule
319 | Luiz Felipe
320 | Nagy Istvn
321 | pembeci
322 | Peter Josling
323 | spacehelmetboy
324 | Bryan Poetz
325 | I. Zakurenyi
326 | Kuno Woudt
327 | Michael Ficarra
328 | michal17
329 | Alex Koloskov
330 | Antonio Murdaca
331 | bestander
332 | Bjarne Heden
333 | Bob Foster
334 | Brandon Williams
335 | bzmwillemsen
336 | Carwin Young
337 | dainstore
338 | Dan Bravender
339 | Daniel Hjelm
340 | Daniel Lager
341 | Dariusz Mlodnicki
342 | Devin Clark
343 | dragos
344 | dskreppsigg
345 | dyuri
346 | eelke
347 | Ekrem Bykkaya
348 | Erik Dasque
349 | Erik Kronberg
350 | erwinmombay
351 | excelenter
352 | fishlevel
353 | Florent Galland
354 | Francesco di Palma
355 | Francisc Romano
356 | Henning Schrder
357 | Hugo Agbonon
358 | Hwulex
359 | iley1
360 | Isaac Z. Schlueter
361 | Ivan Nikoli
362 | James Westgate
363 | James Campos
364 | Januardo Kusuma
365 | jdduarte
366 | jdharding
367 | jose48
368 | Justin Yost
369 | karl58
370 | Kasper Souren
371 | Koryl Prince
372 | kris80
373 | Kristofor Carle
374 | matjazl
375 | Matthew Dierker
376 | mcw0933
377 | mihaipaun01
378 | mr.pohoda
379 | naoyuki.kanezawa
380 | Nikita Vasilyev
381 | Nikki Stevens
382 | Radovan Lozej
383 | Rob Alarcon
384 | roger56
385 | sngsheftel
386 | snorremd
387 | steele
388 | Stefan Huber (Signalwerk)
389 | tanel
390 | Tom Parker
391 | Travis Heeter
392 | UniqueVN
393 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | all: manual.html
2 |
3 | manual.html: manual.txt asciidoc.conf
4 | PATH=../node_modules/codemirror/bin:$(PATH) asciidoc --backend=html5 -o manual.html manual.txt
5 |
--------------------------------------------------------------------------------
/doc/asciidoc.conf:
--------------------------------------------------------------------------------
1 | [miscellaneous]
2 | newline=\n
3 |
4 | [attributes]
5 | disable-javascript=True
6 | warnings=False
7 | #pygments=True
8 | highlight=True
9 |
10 | [literal-inlinemacro]
11 | {passtext}
12 |
13 | [sect0]
14 | {id? }{title}
15 | |
16 |
17 | [sect1]
18 | {id? }{title}
19 | |
20 |
21 | [sect2]
22 | {id? }{title}
23 | |
24 |
25 | [sect3]
26 | {id? }{title}
27 | |
28 |
29 | [paragraph]
30 | {id? }{title?
{title}
}
31 | |
32 |
33 |
34 | [listtags-labeled]
35 | list=|
36 | term=|
37 | item=|
38 | text=|
39 |
40 | [header]
41 |
42 |
43 |
44 |
45 | {doctitle}
46 |
47 |
48 |
56 | {doctitle}
57 |
58 | [footer]
59 |
60 |
61 | [source-highlight-block]
62 |
63 | |
64 |
65 |
66 | [blockdef-listing]
67 | filter=../node_modules/codemirror/bin/source-highlight -s {language}
68 | delimiter=^-{4,}$
69 | template=source-highlight-block
70 | subs=verbatim
71 |
--------------------------------------------------------------------------------
/doc/demo/demo.css:
--------------------------------------------------------------------------------
1 | .CodeMirror {
2 | border: 1px solid silver;
3 | height: 400px;
4 | line-height: 1.3;
5 | font-size: 13pt;
6 | font-family: "Ubuntu Mono", monospace;
7 | z-index: 2;
8 | }
9 | .CodeMirror pre {
10 | padding: 0 9px;
11 | }
12 | .CodeMirror-linenumber {
13 | font-size: 80%;
14 | padding-top: 2px;
15 | }
16 |
17 | ul.tabs {
18 | list-style: none;
19 | margin: 0 0 -1px 0;
20 | padding: 0 0 0 37px;
21 | font-family: "Ubuntu Mono", monospace;
22 | overflow: hidden;
23 | }
24 | ul.tabs li {
25 | font-size: 11pt;
26 | color: #777;
27 | cursor: pointer;
28 | margin: 0 2px 0 0;
29 | padding: 2px 10px 5px;
30 | border: 1px solid silver;
31 | border-bottom-width: 0px;
32 | background: #f3f3f3;
33 | display: inline-block;
34 | z-index: 1;
35 | border-top-left-radius: 6px;
36 | border-top-right-radius: 6px;
37 | position: relative;
38 | }
39 | ul.tabs li:hover {
40 | color: #444;
41 | }
42 | ul.tabs li.selected {
43 | background: white;
44 | color: #222;
45 | z-index: 3;
46 | cursor: default;
47 | }
48 | ul.tabs li:before,
49 | ul.tabs li:after {
50 | position: absolute;
51 | bottom: 0;
52 | width: 6px;
53 | height: 6px;
54 | content: " ";
55 | border: 1px solid silver;
56 | }
57 | ul.tabs li:before {
58 | left: -7px;
59 | border-bottom-right-radius: 6px;
60 | border-width: 0 1px 1px 0;
61 | box-shadow: 2px 2px 0 #f3f3f3;
62 | }
63 | ul.tabs li:after {
64 | right: -7px;
65 | border-bottom-left-radius: 6px;
66 | border-width: 0 0 1px 1px;
67 | box-shadow: -2px 2px 0 #f3f3f3;
68 | }
69 | ul.tabs li.selected:before {
70 | box-shadow: 2px 2px 0 white;
71 | }
72 | ul.tabs li.selected:after {
73 | box-shadow: -2px 2px 0 white;
74 | }
75 |
76 | #menus {
77 | position: absolute;
78 | right: 0;
79 | top: 0;
80 | }
81 | #menus select {
82 | font-family: "Ubuntu Mono", monospace;
83 | font-size: 11pt;
84 | width: 8em;
85 | }
86 |
87 | .CodeMirror div.CodeMirror-cursor {
88 | border-left: 2px solid #444;
89 | }
90 |
91 | .CodeMirror-hint { font-size: 12pt; }
92 |
--------------------------------------------------------------------------------
/doc/demo/demo.js:
--------------------------------------------------------------------------------
1 | var project
2 |
3 | function Project(name, place, config, docs) {
4 | this.name = name
5 | this.docs = Object.create(null)
6 | this.tabs = place.appendChild(document.createElement("ul"))
7 | this.tabs.className = "tabs"
8 | var self = this
9 | CodeMirror.on(this.tabs, "click", function(e) {
10 | var target = e.target || e.srcElement
11 | if (target.nodeName.toLowerCase() != "li") return
12 | var doc = self.findDoc(target.textContent)
13 | if (doc) self.selectDoc(doc)
14 | })
15 |
16 | var myConf = {
17 | switchToDoc: function(name) { self.selectDoc(self.findDoc(name)) },
18 | useWorker: false
19 | }
20 | for (var prop in config) myConf[prop] = config[prop]
21 | var server = this.server = new CodeMirror.TernServer(myConf)
22 |
23 | var firstDoc
24 | for (var name in docs) {
25 | var data = this.registerDoc(name, new CodeMirror.Doc(docs[name], "javascript"))
26 | if (!firstDoc) firstDoc = data
27 | }
28 | this.curDoc = firstDoc
29 | this.setSelectedTab(firstDoc)
30 |
31 | var keyMap = {
32 | "Ctrl-I": function(cm) { server.showType(cm); },
33 | "Ctrl-O": function(cm) { server.showDocs(cm); },
34 | "Ctrl-Space": function(cm) { server.complete(cm); },
35 | "Alt-.": function(cm) { server.jumpToDef(cm); },
36 | "Alt-,": function(cm) { server.jumpBack(cm); },
37 | "Ctrl-Q": function(cm) { server.rename(cm); }
38 | }
39 | this.editor = new CodeMirror(place, {
40 | lineNumbers: true,
41 | extraKeys: keyMap,
42 | matchBrackets: true,
43 | value: firstDoc.doc
44 | })
45 | this.editor.on("cursorActivity", function(cm) { server.updateArgHints(cm); })
46 | }
47 |
48 | Project.prototype = {
49 | findDoc: function(name) { return this.docs[name] },
50 |
51 | registerDoc: function(name, doc) {
52 | this.server.addDoc(name, doc)
53 | var data = this.docs[name] = {
54 | name: name,
55 | doc: doc,
56 | tab: this.tabs.appendChild(document.createElement("li"))
57 | }
58 | data.tab.textContent = name
59 | return data
60 | },
61 |
62 | unregisterDoc: function(doc) {
63 | this.server.delDoc(doc.name)
64 | delete this.docs[doc.name]
65 | this.tabs.removeChild(doc.tab)
66 | if (this.curDoc == doc) for (var n in this.docs) return this.selectDoc(this.docs[n])
67 | },
68 |
69 | setSelectedTab: function(doc) {
70 | for (var n = this.tabs.firstChild; n; n = n.nextSibling)
71 | n.className = n.textContent == doc.name ? "selected" : ""
72 | },
73 |
74 | selectDoc: function(doc) {
75 | if (doc == this.curDoc) return
76 | this.server.hideDoc(this.curDoc)
77 | this.setSelectedTab(doc)
78 | this.curDoc = doc
79 | this.editor.swapDoc(doc.doc)
80 | }
81 | }
82 |
83 | // Initialization
84 |
85 | function load(file, c) {
86 | var xhr = new XMLHttpRequest();
87 | xhr.open("get", file, true);
88 | xhr.send();
89 | xhr.onreadystatechange = function() {
90 | if (xhr.readyState == 4) c(xhr.responseText, xhr.status);
91 | };
92 | }
93 |
94 | CodeMirror.on(window, "load", function() {
95 | var cmds = document.getElementById("commands")
96 | CodeMirror.on(cmds, "change", function() {
97 | if (!project || cmds.selectedIndex == 0) return
98 | var found = commands[cmds.value]
99 | cmds.selectedIndex = 0
100 | project.editor.focus()
101 | if (found) found()
102 | })
103 |
104 | var projects = document.getElementById("projects")
105 | var projectNames = []
106 | var projectTags = document.querySelectorAll("project")
107 | for (var i = 0; i < projectTags.length; i++) {
108 | var opt = projects.appendChild(document.createElement("option"))
109 | projectNames.push(opt.textContent = projectTags[i].id)
110 | }
111 | CodeMirror.on(projects, "change", function() {
112 | if (projects.selectedIndex != 0)
113 | initProject(projects.value, function() {
114 | projects.selectedIndex = 0
115 | project.editor.focus()
116 | })
117 | })
118 | function updateFromHash() {
119 | var name = location.hash.slice(1)
120 | if (projectNames.indexOf(name) > -1 &&
121 | (!project || project.name != name)) {
122 | initProject(name)
123 | return true
124 | }
125 | }
126 | CodeMirror.on(window, "hashchange", updateFromHash)
127 |
128 | updateFromHash() || initProject("simple")
129 | })
130 |
131 | function loadFiles(project, c) {
132 | var found = {}
133 | function inner(node) {
134 | while (node && node.nodeName != "PRE") node = node.nextSibling
135 | if (!node) return c(found)
136 | if (node.hasAttribute("file")) {
137 | load(node.getAttribute("file"), function(data) {
138 | found[node.id] = data
139 | inner(node.nextSibling)
140 | })
141 | } else {
142 | found[node.id] = node.textContent
143 | inner(node.nextSibling)
144 | }
145 | }
146 | inner(project.firstChild)
147 | }
148 |
149 | var defsLoaded = Object.create(null)
150 | function loadDefs(defs, c) {
151 | var result = [], loaded = 0
152 | for (var i = 0; i < defs.length; ++i) (function(i) {
153 | var name = defs[i]
154 | if (defsLoaded[name]) {
155 | result[i] = defsLoaded[name]
156 | if (++loaded == defs.length) c(result)
157 | } else {
158 | load("../../defs/" + name + ".json", function(json) {
159 | defsLoaded[name] = result[i] = JSON.parse(json)
160 | if (++loaded == defs.length) c(result)
161 | })
162 | }
163 | })(i)
164 | }
165 |
166 | function words(str) {
167 | return str ? str.split(" ") : []
168 | }
169 |
170 | function initProject(name, c) {
171 | var node = document.getElementById(name)
172 | loadDefs(words(node.getAttribute("data-libs")), function(defs) {
173 | var plugins = {}
174 | words(node.getAttribute("data-plugins")).forEach(function(name) { plugins[name] = true })
175 |
176 | if (plugins.requirejs) plugins.requirejs = {override: {"jquery": "=$"}}
177 |
178 | loadFiles(node, function(files) {
179 | var place = document.getElementById("place")
180 | place.textContent = ""
181 |
182 | if (project) project.server.destroy()
183 |
184 | project = new Project(name, place, {
185 | defs: defs,
186 | plugins: plugins
187 | }, files)
188 | location.hash = "#" + name
189 | c && c()
190 | })
191 | })
192 | }
193 |
194 | var commands = {
195 | complete: function() { project.server.complete(project.editor) },
196 | jumptodef: function() { project.server.jumpToDef(project.editor) },
197 | finddocs: function() { project.server.showDocs(project.editor) },
198 | findtype: function() { project.server.showType(project.editor) },
199 | rename: function() { project.server.rename(project.editor) },
200 | addfile: function() {
201 | var name = prompt("Name of the new buffer", "")
202 | if (name == null) return
203 | if (!name) name = "test"
204 | var i = 0
205 | while (project.findDoc(name + (i || ""))) ++i
206 | project.selectDoc(project.registerDoc(name + (i || ""), new CodeMirror.Doc("", "javascript")))
207 | },
208 | delfile: function() {
209 | var hasDoc = false
210 | for (var _ in project.docs) { hasDoc = true; break }
211 | if (hasDoc) project.unregisterDoc(project.curDoc)
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/doc/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Tern Demo
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
46 |
47 | Tern demo
48 |
49 | This editor is hooked up to Tern. The drop-down in the top right
50 | corner lists the commands and keyboard shortcuts available. Output and
51 | function argument hints will appear in the bar below the editor.
52 |
53 |
54 |
69 |
70 |
71 |
72 |
73 |
76 |
77 | // Use ctrl-space to complete something
78 | co
79 | document.body.a
80 |
81 | // Put the cursor in or after an expression, press ctrl-i to
82 | // find its type
83 |
84 | var foo = ["array", "of", "strings"]
85 | var bar = foo.slice(0, 2).join("").split("a")[0]
86 |
87 | // Works for locally defined types too.
88 |
89 | function CTor() { this.size = 10 }
90 | CTor.prototype.hallo = "hallo"
91 |
92 | var baz = new CTor
93 | baz.
94 |
95 | // You can press ctrl-q when the cursor is on a variable
96 | // name to rename it. Try it with CTor...
97 |
98 | // When the cursor is in an argument list, the arguments
99 | // are shown below the editor.
100 |
101 | [1].reduce( )
102 |
103 |
104 |
105 |
108 |
109 | // A simple set of three modules, connected with requirejs
110 |
111 | requirejs(["text_util", "output"], function(text, output) {
112 | window.addEventListener("load", function() {
113 | // Pressing alt-. on `garble` jumps to the module
114 | var word = text.capitalize(text.garble(prompt("Hi", "")))
115 | output.write(word)
116 | })
117 | })
118 |
119 |
120 |
121 | // Trivial requirejs-style module
122 |
123 | define(function() {
124 | return {
125 | // Capitalize a string
126 | capitalize: function(word) {
127 | return word.charAt(0).toUpperCase() + word.slice(1)
128 | },
129 |
130 | // Garble the vowels in a string
131 | garble: function(word) {
132 | return word.replace(/[auiyoe]/g, function() {
133 | return "auiyoe".charAt(Math.floor(Math.random() * 6))
134 | })
135 | }
136 | }
137 | })
138 |
139 |
140 |
141 | // This one is written using a multi-module-loader wrapper
142 | //
143 | // If Tern's requirejs plugin is loaded, it'll pick up the
144 | // call to define. Alternatively, when its commonjs plugin
145 | // is loaded, that'll handle the require calls.
146 |
147 | (function(root, mod) {
148 | if (typeof exports == "object" && typeof module == "object")
149 | mod(exports, require("jquery")) // CommonJS
150 | else if (typeof define == "function" && define.amd)
151 | define(["exports", "jquery"], mod) // AMD
152 | else
153 | mod(root.output = {}, root.$) // Plain browser env
154 | })(this, function(exports, $) {
155 |
156 | // Write some text to the bottom of the document
157 | exports.write = function(text) {
158 | $("body").append($(" ").text(text))
159 | }
160 |
161 | })
162 |
163 |
164 |
167 |
168 | // Tern can do ECMAScript 6 (2015) too!
169 |
170 | // Imports and exports work. You can complete module names, and
171 | // jump to the definition of things defined in modules.
172 |
173 | // (Press alt-. on `List` to jump to the class definition)
174 | import {List} from "./list"
175 |
176 | import * as myMath from "./mymath"
177 |
178 | const l = List.of(3, 4, 5)
179 | for (let elt of l.map(x => x * 2)) {
180 | // Tern knows that `elt` is a number!
181 | let output = myMath.halve(elt)
182 | console.log(output)
183 | }
184 |
185 | // Raw template string
186 | let raw = String.raw`\n`
187 |
188 | // Default arguments
189 | Array.of(1, 2, 3, 4).find(x => x % 3 == 0)
190 |
191 |
192 |
193 | export class List {
194 | constructor(head, tail) {
195 | this.head = head
196 | this.tail = tail
197 | }
198 |
199 | static of(...elements) {
200 | let result = null
201 | for (let i = elements.length - 1; i >= 0; i--)
202 | result = new List(elements[i], result)
203 | return result
204 | }
205 |
206 | map(f) {
207 | return new List(f(this.head), this.tail && this.tail.map(f))
208 | }
209 |
210 | *[Symbol.iterator]() {
211 | for (let pos = this; pos; pos = pos.tail)
212 | yield pos.head
213 | }
214 | }
215 |
216 |
217 |
218 | export const PI = 3
219 |
220 | export const halve = x => x / 2
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
--------------------------------------------------------------------------------
/doc/demo/polyfill.js:
--------------------------------------------------------------------------------
1 | // Shims to fill in enough of ECMAScript 5 to make Tern run. Does not
2 | // supply standard-compliant methods, in that some functionality is
3 | // left out (such as second argument to Object.create, self args in
4 | // array methods, etc). WILL clash with other ECMA5 polyfills in a
5 | // probably disruptive way.
6 |
7 | (function() {
8 | Object.create = Object.create || (function() {
9 | if (!({__proto__: null} instanceof Object))
10 | return function(base) { return {__proto__: base}; };
11 | function ctor() {}
12 | var frame = document.body.appendChild(document.createElement("iframe"));
13 | frame.src = "javascript:";
14 | var empty = frame.contentWindow.Object.prototype;
15 | delete empty.hasOwnProperty;
16 | delete empty.isPrototypeOf;
17 | delete empty.propertyIsEnumerable;
18 | delete empty.valueOf;
19 | delete empty.toString;
20 | delete empty.toLocaleString;
21 | delete empty.constructor;
22 | return function(base) { ctor.prototype = base || empty; return new ctor(); };
23 | })();
24 |
25 | // Array methods
26 |
27 | var AP = Array.prototype;
28 |
29 | AP.some = AP.some || function(pred) {
30 | for (var i = 0; i < this.length; ++i) if (pred(this[i], i)) return true;
31 | };
32 |
33 | AP.forEach = AP.forEach || function(f) {
34 | for (var i = 0; i < this.length; ++i) f(this[i], i);
35 | };
36 |
37 | AP.indexOf = AP.indexOf || function(x, start) {
38 | for (var i = start || 0; i < this.length; ++i) if (this[i] === x) return i;
39 | return -1;
40 | };
41 |
42 | AP.lastIndexOf = AP.lastIndexOf || function(x, start) {
43 | for (var i = start == null ? this.length - 1 : start; i >= 0; ++i) if (this[i] === x) return i;
44 | return -1;
45 | };
46 |
47 | AP.map = AP.map || function(f) {
48 | for (var r = [], i = 0; i < this.length; ++i) r.push(f(this[i], i));
49 | return r;
50 | };
51 |
52 | Array.isArray = Array.isArray || function(v) {
53 | return Object.prototype.toString.call(v) == "[object Array]";
54 | };
55 |
56 | String.prototype.trim = String.prototype.trim || function() {
57 | var from = 0, to = this.length;
58 | while (/\s/.test(this.charAt(from))) ++from;
59 | while (/\s/.test(this.charAt(to - 1))) --to;
60 | return this.slice(from, to);
61 | };
62 |
63 | /*! JSON v3.2.4 | http://bestiejs.github.com/json3 | Copyright 2012, Kit Cambridge | http://kit.mit-license.org */
64 | if (!window.JSON) (function(){var e=void 0,i=!0,k=null,l={}.toString,m,n,p="function"===typeof define&&define.c,q=!p&&"object"==typeof exports&&exports;q||p?"object"==typeof JSON&&JSON?p?q=JSON:(q.stringify=JSON.stringify,q.parse=JSON.parse):p&&(q=this.JSON={}):q=this.JSON||(this.JSON={});var r,t,u,x,z,B,C,D,E,F,G,H,I,J=new Date(-3509827334573292),K,O,P;try{J=-109252==J.getUTCFullYear()&&0===J.getUTCMonth()&&1==J.getUTCDate()&&10==J.getUTCHours()&&37==J.getUTCMinutes()&&6==J.getUTCSeconds()&&708==J.getUTCMilliseconds()}catch(Q){}
65 | function R(b){var c,a,d,j=b=="json";if(j||b=="json-stringify"||b=="json-parse"){if(b=="json-stringify"||j){if(c=typeof q.stringify=="function"&&J){(d=function(){return 1}).toJSON=d;try{c=q.stringify(0)==="0"&&q.stringify(new Number)==="0"&&q.stringify(new String)=='""'&&q.stringify(l)===e&&q.stringify(e)===e&&q.stringify()===e&&q.stringify(d)==="1"&&q.stringify([d])=="[1]"&&q.stringify([e])=="[null]"&&q.stringify(k)=="null"&&q.stringify([e,l,k])=="[null,null,null]"&&q.stringify({A:[d,i,false,k,"\x00\u0008\n\u000c\r\t"]})==
66 | '{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'&&q.stringify(k,d)==="1"&&q.stringify([1,2],k,1)=="[\n 1,\n 2\n]"&&q.stringify(new Date(-864E13))=='"-271821-04-20T00:00:00.000Z"'&&q.stringify(new Date(864E13))=='"+275760-09-13T00:00:00.000Z"'&&q.stringify(new Date(-621987552E5))=='"-000001-01-01T00:00:00.000Z"'&&q.stringify(new Date(-1))=='"1969-12-31T23:59:59.999Z"'}catch(f){c=false}}if(!j)return c}if(b=="json-parse"||j){if(typeof q.parse=="function")try{if(q.parse("0")===0&&!q.parse(false)){d=
67 | q.parse('{"A":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}');if(a=d.a.length==5&&d.a[0]==1){try{a=!q.parse('"\t"')}catch(o){}if(a)try{a=q.parse("01")!=1}catch(g){}}}}catch(h){a=false}if(!j)return a}return c&&a}}
68 | if(!R("json")){J||(K=Math.floor,O=[0,31,59,90,120,151,181,212,243,273,304,334],P=function(b,c){return O[c]+365*(b-1970)+K((b-1969+(c=+(c>1)))/4)-K((b-1901+c)/100)+K((b-1601+c)/400)});if(!(m={}.hasOwnProperty))m=function(b){var c={},a;if((c.__proto__=k,c.__proto__={toString:1},c).toString!=l)m=function(a){var b=this.__proto__,a=a in(this.__proto__=k,this);this.__proto__=b;return a};else{a=c.constructor;m=function(b){var c=(this.constructor||a).prototype;return b in this&&!(b in c&&this[b]===c[b])}}c=
69 | k;return m.call(this,b)};n=function(b,c){var a=0,d,j,f;(d=function(){this.valueOf=0}).prototype.valueOf=0;j=new d;for(f in j)m.call(j,f)&&a++;d=j=k;if(a)a=a==2?function(a,b){var c={},d=l.call(a)=="[object Function]",f;for(f in a)!(d&&f=="prototype")&&!m.call(c,f)&&(c[f]=1)&&m.call(a,f)&&b(f)}:function(a,b){var c=l.call(a)=="[object Function]",d,f;for(d in a)!(c&&d=="prototype")&&m.call(a,d)&&!(f=d==="constructor")&&b(d);(f||m.call(a,d="constructor"))&&b(d)};else{j=["valueOf","toString","toLocaleString",
70 | "propertyIsEnumerable","isPrototypeOf","hasOwnProperty","constructor"];a=function(a,b){var c=l.call(a)=="[object Function]",d;for(d in a)!(c&&d=="prototype")&&m.call(a,d)&&b(d);for(c=j.length;d=j[--c];m.call(a,d)&&b(d));}}a(b,c)};R("json-stringify")||(r={"\\":"\\\\",'"':'\\"',"\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t"},t=function(b,c){return("000000"+(c||0)).slice(-b)},u=function(b){for(var c='"',a=0,d;d=b.charAt(a);a++)c=c+('\\"\u0008\u000c\n\r\t'.indexOf(d)>-1?r[d]:r[d]=d<" "?
71 | "\\u00"+t(2,d.charCodeAt(0).toString(16)):d);return c+'"'},x=function(b,c,a,d,j,f,o){var g=c[b],h,s,v,w,L,M,N,y,A;if(typeof g=="object"&&g){h=l.call(g);if(h=="[object Date]"&&!m.call(g,"toJSON"))if(g>-1/0&&g<1/0){if(P){v=K(g/864E5);for(h=K(v/365.2425)+1970-1;P(h+1,0)<=v;h++);for(s=K((v-P(h,0))/30.42);P(h,s+1)<=v;s++);v=1+v-P(h,s);w=(g%864E5+864E5)%864E5;L=K(w/36E5)%24;M=K(w/6E4)%60;N=K(w/1E3)%60;w=w%1E3}else{h=g.getUTCFullYear();s=g.getUTCMonth();v=g.getUTCDate();L=g.getUTCHours();M=g.getUTCMinutes();
72 | N=g.getUTCSeconds();w=g.getUTCMilliseconds()}g=(h<=0||h>=1E4?(h<0?"-":"+")+t(6,h<0?-h:h):t(4,h))+"-"+t(2,s+1)+"-"+t(2,v)+"T"+t(2,L)+":"+t(2,M)+":"+t(2,N)+"."+t(3,w)+"Z"}else g=k;else if(typeof g.toJSON=="function"&&(h!="[object Number]"&&h!="[object String]"&&h!="[object Array]"||m.call(g,"toJSON")))g=g.toJSON(b)}a&&(g=a.call(c,b,g));if(g===k)return"null";h=l.call(g);if(h=="[object Boolean]")return""+g;if(h=="[object Number]")return g>-1/0&&g<1/0?""+g:"null";if(h=="[object String]")return u(g);if(typeof g==
73 | "object"){for(b=o.length;b--;)if(o[b]===g)throw TypeError();o.push(g);y=[];c=f;f=f+j;if(h=="[object Array]"){s=0;for(b=g.length;s0){d="";for(a>10&&(a=10);d.length-1)H++;else{if("{}[]:,".indexOf(a)>-1){H++;return a}if(a=='"'){d="@";for(H++;H-1){d=d+B[a];H++}else if(a=="u"){j=++H;for(f=H+4;H="0"&&a<="9"||a>="a"&&a<="f"||a>="A"&&a<="F"||C()}d=d+z("0x"+b.slice(j,H))}else C()}else{if(a=='"')break;
76 | d=d+a;H++}}if(b.charAt(H)=='"'){H++;return d}}else{j=H;if(a=="-"){o=i;a=b.charAt(++H)}if(a>="0"&&a<="9"){for(a=="0"&&(a=b.charAt(H+1),a>="0"&&a<="9")&&C();H="0"&&a<="9");H++);if(b.charAt(H)=="."){for(f=++H;f="0"&&a<="9");f++);f==H&&C();H=f}a=b.charAt(H);if(a=="e"||a=="E"){a=b.charAt(++H);(a=="+"||a=="-")&&H++;for(f=H;f="0"&&a<="9");f++);f==H&&C();H=f}return+b.slice(j,H)}o&&C();if(b.slice(H,H+4)=="true"){H=H+4;return i}if(b.slice(H,H+5)==
77 | "false"){H=H+5;return false}if(b.slice(H,H+4)=="null"){H=H+4;return k}}C()}}return"$"},E=function(b){var c,a;b=="$"&&C();if(typeof b=="string"){if(b.charAt(0)=="@")return b.slice(1);if(b=="["){for(c=[];;a||(a=i)){b=D();if(b=="]")break;if(a)if(b==","){b=D();b=="]"&&C()}else C();b==","&&C();c.push(E(b))}return c}if(b=="{"){for(c={};;a||(a=i)){b=D();if(b=="}")break;if(a)if(b==","){b=D();b=="}"&&C()}else C();(b==","||typeof b!="string"||b.charAt(0)!="@"||D()!=":")&&C();c[b.slice(1)]=E(D())}return c}C()}return b},
78 | G=function(b,c,a){a=F(b,c,a);a===e?delete b[c]:b[c]=a},F=function(b,c,a){var d=b[c],j;if(typeof d=="object"&&d)if(l.call(d)=="[object Array]")for(j=d.length;j--;)G(d,j,a);else n(d,function(b){G(d,b,a)});return a.call(b,c,d)},q.parse=function(b,c){var a,d;H=0;I=b;a=E(D());D()!="$"&&C();H=I=k;return c&&l.call(c)=="[object Function]"?F((d={},d[""]=a,d),"",c):a})}p&&define(function(){return q});
79 | }());
80 | })();
81 |
--------------------------------------------------------------------------------
/doc/docs.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Signika';
3 | font-style: normal;
4 | font-weight: 700;
5 | src: local('Signika-Bold'), url(http://themes.googleusercontent.com/static/fonts/signika/v3/7M5kxD4eGxuhgFaIk95pBRsxEYwM7FgeyaSgU71cLG0.woff) format('woff');
6 | }
7 |
8 | @font-face {
9 | font-family: 'Ubuntu Mono';
10 | font-style: normal;
11 | font-weight: 500;
12 | src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url('http://themes.googleusercontent.com/static/fonts/ubuntumono/v3/ViZhet7Ak-LRXZMXzuAfkYbN6UDyHWBl620a-IRfuBk.woff') format('woff');
13 | }
14 |
15 | body {
16 | font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif;
17 | color: #222;
18 | font-size: 11pt;
19 | max-width: 700px;
20 | margin: 0 0 0 60px;
21 | padding: 60px 0 4em;
22 | }
23 |
24 | #top {
25 | position: fixed;
26 | top: 0;
27 | background: white;
28 | padding-top: 15px;
29 | left: 20px; right: 20px;
30 | z-index: 5;
31 | }
32 |
33 | #head {
34 | border-radius: 5px;
35 | background: #1c5b64;
36 | box-shadow: 0px 3px 3px rgba(0, 0, 0, .5);
37 | position: relative;
38 | font-family: "Signika", sans-serif;
39 | font-weight: 700;
40 | }
41 |
42 | #head > a {
43 | border-right: 1px solid #276c81;
44 | display: inline-block;
45 | height: 25px;
46 | padding: 5px 20px;
47 | color: white;
48 | text-decoration: none;
49 | line-height: 25px;
50 | font-size: 17px;
51 | }
52 |
53 | #head > a.title {
54 | font-size: 20px;
55 | line-height: 24px;
56 | padding-left: 80px;
57 | background: url(logo.png);
58 | background-position: 40px center;
59 | background-size: auto 80%;
60 | background-repeat: no-repeat;
61 | border-bottom-left-radius: 5px;
62 | border-top-left-radius: 5px;
63 | }
64 |
65 | #head > a:hover {
66 | background-color: #276c81 !important;
67 | }
68 |
69 | .title span {
70 | font-size: 13px;
71 | }
72 |
73 | code, pre { font-family: "Ubuntu Mono", monospace; }
74 | code { color: #124f55; font-size: 110%; }
75 | pre {
76 | border-left: 3px solid #def;
77 | padding: 2px 0 2px 10px;
78 | }
79 |
80 | h1, h2, h3, h4 {
81 | font-family: "Signika", sans-serif;
82 | font-weight: 700;
83 | color: #124f55;
84 | }
85 | h1 { font-size: 20pt; }
86 | h2 { font-size: 17pt; }
87 | h3 { font-size: 13pt; }
88 | h4 { font-size: 11pt; }
89 |
90 | a, a:visited, a code { color: #df4c11; text-decoration: none; }
91 | a:hover { text-decoration: underline; }
92 |
93 | ul, ol {
94 | margin: 0;
95 | padding: 0;
96 | }
97 | li {
98 | margin-left: 1.5em;
99 | padding: 0;
100 | }
101 |
102 | li p { margin: 0; }
103 | dd p:first-child { margin-top: 1px; }
104 | dd { margin-left: 20px; }
105 | dt { text-indent: -1em; padding-left: 1em; }
106 |
107 | a[id] {
108 | position: relative;
109 | display: inline-block;
110 | vertical-align: top;
111 | top: -60px;
112 | }
113 |
114 | .release-note {
115 | margin-left: 1em;
116 | }
117 |
118 | /* CodeMirror default theme for highlighting */
119 |
120 | .cm-s-default .cm-keyword {color: #708;}
121 | .cm-s-default .cm-atom {color: #219;}
122 | .cm-s-default .cm-number {color: #164;}
123 | .cm-s-default .cm-def {color: #00f;}
124 | .cm-s-default .cm-variable {color: black;}
125 | .cm-s-default .cm-variable-2 {color: #05a;}
126 | .cm-s-default .cm-variable-3 {color: #085;}
127 | .cm-s-default .cm-property {color: black;}
128 | .cm-s-default .cm-operator {color: black;}
129 | .cm-s-default .cm-comment {color: #a50;}
130 | .cm-s-default .cm-string {color: #a11;}
131 | .cm-s-default .cm-string-2 {color: #f50;}
132 | .cm-s-default .cm-meta {color: #555;}
133 | .cm-s-default .cm-error {color: #f00;}
134 | .cm-s-default .cm-qualifier {color: #555;}
135 | .cm-s-default .cm-builtin {color: #30a;}
136 | .cm-s-default .cm-bracket {color: #997;}
137 | .cm-s-default .cm-tag {color: #170;}
138 | .cm-s-default .cm-attribute {color: #00c;}
139 | .cm-s-default .cm-header {color: blue;}
140 | .cm-s-default .cm-quote {color: #090;}
141 | .cm-s-default .cm-hr {color: #999;}
142 | .cm-s-default .cm-link {color: #00c;}
143 |
--------------------------------------------------------------------------------
/doc/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ternjs/tern/33316af5be6cee834114c6dd4628f7eec1da4138/doc/logo.png
--------------------------------------------------------------------------------
/emacs/tern-auto-complete.el:
--------------------------------------------------------------------------------
1 | ;;; tern-auto-complete.el --- Tern Completion by auto-complete.el -*- lexical-binding: t -*-
2 |
3 | ;; Author:
4 | ;; Version: 0.0.1
5 | ;; Package-Requires: ((tern "0.0.1") (auto-complete "1.4") (cl-lib "0.5") (emacs "24"))
6 |
7 | ;;; Commentary:
8 |
9 | ;; Display completion items with its type and document.
10 |
11 | ;; If `tern-ac-on-dot' is non-nil (default), typing '.(dot)' invokes auto-complete with tern.
12 | ;; Calling the command `tern-ac-complete', you can invoke auto-complete manually.
13 | ;; This program does not provide an ac-source for arbitrary timing yet.
14 |
15 | ;;; Installation:
16 |
17 | ;; Add following lines below the tern setup code.
18 |
19 | ;; (eval-after-load 'tern
20 | ;; '(progn
21 | ;; (require 'tern-auto-complete)
22 | ;; (tern-ac-setup)))
23 |
24 | ;;; Code:
25 |
26 | (require 'cl-lib)
27 | (require 'tern)
28 | (require 'auto-complete)
29 |
30 |
31 |
32 | ;;; Completion
33 |
34 | (defcustom tern-ac-on-dot t
35 | "[AC] If t, tern enable completion by auto-completion."
36 | :type 'boolean
37 | :group 'auto-complete)
38 |
39 | (defcustom tern-ac-sync t
40 | "[AC] If t, auto-complete will wait for tern canditates before starting.
41 | This enables tern canditates to integrate automatically in auto-complete without
42 | the need for a separate keybinding.
43 |
44 | Remember to add ac-source-tern-completion to ac-sources."
45 | :type 'boolean
46 | :group 'auto-complete)
47 |
48 |
49 | (defvar tern-ac-complete-reply nil "[internal] tern-ac-complete-reply.")
50 |
51 | (defvar tern-ac-complete-request-point 0
52 | "[internal] The point where `tern-ac-complete-request' is called.")
53 |
54 | (defun tern-ac-complete-request (cc)
55 | (setq tern-last-point-pos (point))
56 | (setq tern-ac-complete-reply nil)
57 | (setq tern-ac-complete-request-point (point))
58 | (tern-run-query
59 | (lambda (data)
60 | (tern-ac-complete-response data)
61 | (funcall cc))
62 | `((type . "completions") (types . t) (docs . t) (caseInsensitive . t))
63 | (point)))
64 |
65 | (defun tern-ac-complete-response (data)
66 | (let ((cs (cl-loop for elt across (cdr (assq 'completions data)) collect elt))
67 | (start (+ 1 (cdr (assq 'start data))))
68 | (end (+ 1 (cdr (assq 'end data)))))
69 | (setq tern-last-completions (list (buffer-substring-no-properties start end) start end cs))
70 | (setq tern-ac-complete-reply cs)))
71 |
72 | (defun tern-ac-complete ()
73 | "Complete code at point by tern."
74 | (interactive)
75 | (tern-ac-complete-request
76 | (lambda ()
77 | (let ((ac-sources (cons 'ac-source-tern-completion ac-sources)))
78 | (ac-start)))))
79 |
80 | (defun tern-ac-dot-complete ()
81 | "Insert dot and complete code at point by tern."
82 | (interactive)
83 | (insert ".")
84 | (unless (nth 4 (syntax-ppss))
85 | (tern-ac-complete)))
86 |
87 | (defvar tern-ac-completion-truncate-length 22
88 | "[AC] truncation length for type summary.")
89 |
90 | (defun tern-ac-completion-matches ()
91 | (mapcar
92 | (lambda (item)
93 | (let ((doc (cdr (assq 'doc item)))
94 | (type (cdr (assq 'type item)))
95 | (name (cdr (assq 'name item))))
96 | (popup-make-item
97 | name
98 | :symbol (if (null type) "?" (if (string-match "fn" type) "f" "v"))
99 | :summary (truncate-string-to-width
100 | (or type "?") tern-ac-completion-truncate-length 0 nil "...")
101 | :document (concat type "\n\n" doc))))
102 | tern-ac-complete-reply))
103 |
104 | (defun tern-ac-completion-prefix ()
105 | (or (ac-prefix-default)
106 | (when (= tern-ac-complete-request-point (point))
107 | tern-ac-complete-request-point)))
108 |
109 | ;; (makunbound 'ac-source-tern-completion)
110 | (ac-define-source tern-completion
111 | '((candidates . tern-ac-completion-matches)
112 | (prefix . tern-ac-completion-prefix)
113 | (requires . -1)))
114 |
115 | ;;;###autoload
116 | (defun tern-ac-setup ()
117 | "Setup auto-complete for tern-mode."
118 | (interactive)
119 | (if tern-ac-on-dot
120 | (define-key tern-mode-keymap "." 'tern-ac-dot-complete)
121 | (define-key tern-mode-keymap "." nil)))
122 |
123 | (defvar tern-ac-js-major-modes '(rjsx-mode js2-mode js2-jsx-mode js-mode js-jsx-mode javascript-mode))
124 |
125 | (defadvice auto-complete (around add-tern-ac-candidates first activate)
126 | "Load tern-js canditates before ac-start."
127 | (if (and tern-ac-sync
128 | (memq major-mode tern-ac-js-major-modes)
129 | (not (or (ac-menu-live-p) (ac-inline-live-p))))
130 | (tern-ac-complete-request
131 | 'auto-complete-1)
132 | ad-do-it))
133 |
134 |
135 | (provide 'tern-auto-complete)
136 | ;;; tern-auto-complete.el ends here
137 |
--------------------------------------------------------------------------------
/lib/bootstrap.js:
--------------------------------------------------------------------------------
1 | var tern = require("./tern");
2 | var fs = require("fs"), path = require("path"), url = require("url");
3 | var glob = require("glob"), minimatch = require("minimatch");
4 | var resolveFrom = require("resolve-from");
5 |
6 | var projectFileName = ".tern-project", portFileName = ".tern-port";
7 |
8 | function findProjectDir() {
9 | var dir = process.cwd();
10 | for (;;) {
11 | try {
12 | if (fs.statSync(path.resolve(dir, projectFileName)).isFile()) return dir;
13 | } catch(e) {}
14 | var shorter = path.dirname(dir);
15 | if (shorter == dir) return null;
16 | dir = shorter;
17 | }
18 | }
19 |
20 | var defaultConfig = {
21 | libs: [],
22 | loadEagerly: false,
23 | plugins: {doc_comment: true},
24 | ecmaScript: true,
25 | ecmaVersion: 9,
26 | dependencyBudget: tern.defaultOptions.dependencyBudget
27 | };
28 | var homeDir = process.env.HOME || process.env.USERPROFILE;
29 | if (homeDir && fs.existsSync(path.resolve(homeDir, ".tern-config")))
30 | defaultConfig = readProjectFile(path.resolve(homeDir, ".tern-config"));
31 |
32 | function readJSON(fileName) {
33 | var file = fs.readFileSync(fileName, "utf8");
34 | try {
35 | return JSON.parse(file);
36 | } catch (e) {
37 | console.error("Bad JSON in " + fileName + ": " + e.message);
38 | process.exit(1);
39 | }
40 | }
41 |
42 | function readProjectFile(fileName) {
43 | var data = readJSON(fileName), name;
44 | for (var option in defaultConfig) {
45 | if (!data.hasOwnProperty(option))
46 | data[option] = defaultConfig[option];
47 | else if (option == "plugins")
48 | for (name in defaultConfig.plugins)
49 | if (!Object.prototype.hasOwnProperty.call(data.plugins, name))
50 | data.plugins[name] = defaultConfig.plugins[name];
51 | }
52 | return data;
53 | }
54 |
55 | function findFile(file, projectDir, fallbackDir, options) {
56 | var local = path.resolve(projectDir, file);
57 | if (!options.disableLoadingLocal && fs.existsSync(local)) return local;
58 | var shared = path.resolve(fallbackDir, file);
59 | if (fs.existsSync(shared)) return shared;
60 | }
61 |
62 | var distDir = path.resolve(__dirname, "..");
63 |
64 | function findDefs(projectDir, config, options) {
65 | var defs = [], src = config.libs.slice();
66 | if (config.ecmaScript && src.indexOf("ecmascript") == -1)
67 | src.unshift("ecmascript");
68 | for (var i = 0; i < src.length; ++i) {
69 | var file = src[i];
70 | if (!/\.json$/.test(file)) file = file + ".json";
71 | var found = findFile(file, projectDir, path.resolve(distDir, "defs"), options)
72 | || resolveFrom(projectDir, "tern-" + src[i]);
73 | if (!found) {
74 | try {
75 | found = require.resolve("tern-" + src[i]);
76 | } catch (e) {
77 | process.stderr.write("Failed to find library " + src[i] + ".\n");
78 | continue;
79 | }
80 | }
81 | if (found) defs.push(readJSON(found));
82 | }
83 | return defs;
84 | }
85 |
86 | function loadPlugins(projectDir, config, options) {
87 | var plugins = config.plugins, options = {};
88 | for (var plugin in plugins) {
89 | var val = plugins[plugin];
90 | if (!val) continue;
91 | var found = findFile(plugin + ".js", projectDir, path.resolve(distDir, "plugin"), options)
92 | || resolveFrom(projectDir, "tern-" + plugin);
93 | if (!found) {
94 | try {
95 | found = require.resolve("tern-" + plugin);
96 | } catch (e) {
97 | process.stderr.write("Failed to find plugin " + plugin + ".\n");
98 | continue;
99 | }
100 | }
101 | var mod = require(found);
102 | if (mod.hasOwnProperty("initialize")) mod.initialize(distDir);
103 | options[path.basename(plugin)] = val;
104 | }
105 |
106 | return options;
107 | }
108 |
109 | function startServer(dir, config, options) {
110 | var defs = findDefs(dir, config, options);
111 | var plugins = loadPlugins(dir, config, options);
112 | var ternConfig = {
113 | getFile: function(name, c) {
114 | if (config.dontLoad && config.dontLoad.some(function(pat) {return minimatch(name, pat)}))
115 | c(null, "");
116 | else
117 | fs.readFile(path.resolve(dir, name), "utf8", c);
118 | },
119 | normalizeFilename: function(name) {
120 | var pt = path.resolve(dir, name);
121 | try { pt = fs.realPathSync(path.resolve(dir, name), true) }
122 | catch(e) {}
123 | return path.relative(dir, pt);
124 | },
125 | async: true,
126 | defs: defs,
127 | plugins: plugins,
128 | projectDir: dir,
129 | ecmaVersion: config.ecmaVersion,
130 | dependencyBudget: config.dependencyBudget,
131 | };
132 | if (options.tern) {
133 | for (var option in options.tern) {
134 | if (options.tern.hasOwnProperty(option)) {
135 | ternConfig[option] = options.tern[option];
136 | }
137 | }
138 | }
139 | var server = new tern.Server(ternConfig);
140 |
141 | if (config.loadEagerly) config.loadEagerly.forEach(function(pat) {
142 | glob.sync(pat, { cwd: dir }).forEach(function(file) {
143 | server.addFile(file);
144 | });
145 | });
146 | server.flush(function(){});
147 | return server;
148 | }
149 |
150 | module.exports = function bootstrapServer(options) {
151 | var projectDir = options.projectDir;
152 | if (!projectDir) {
153 | projectDir = findProjectDir();
154 | }
155 |
156 | if (projectDir) {
157 | var config = readProjectFile(path.resolve(projectDir, projectFileName));
158 | } else {
159 | projectDir = process.cwd();
160 | var config = defaultConfig;
161 | }
162 | return startServer(projectDir, config, options);
163 | }
164 |
--------------------------------------------------------------------------------
/lib/comment.js:
--------------------------------------------------------------------------------
1 | (function(mod) {
2 | if (typeof exports == "object" && typeof module == "object") // CommonJS
3 | return mod(exports);
4 | if (typeof define == "function" && define.amd) // AMD
5 | return define(["exports"], mod);
6 | mod(tern.comment || (tern.comment = {}));
7 | })(function(exports) {
8 | function isSpace(ch) {
9 | return (ch < 14 && ch > 8) || ch === 32 || ch === 160;
10 | }
11 |
12 | function onOwnLine(text, pos) {
13 | for (; pos > 0; --pos) {
14 | var ch = text.charCodeAt(pos - 1);
15 | if (ch == 10) break;
16 | if (!isSpace(ch)) return false;
17 | }
18 | return true;
19 | }
20 |
21 | // Gather comments directly before a function
22 | exports.commentsBefore = function(text, pos) {
23 | var found = null, emptyLines = 0, topIsLineComment;
24 | out: while (pos > 0) {
25 | var prev = text.charCodeAt(pos - 1);
26 | if (prev == 10) {
27 | for (var scan = --pos, sawNonWS = false; scan > 0; --scan) {
28 | prev = text.charCodeAt(scan - 1);
29 | if (prev == 47 && text.charCodeAt(scan - 2) == 47) {
30 | if (!onOwnLine(text, scan - 2)) break out;
31 | var content = text.slice(scan, pos);
32 | if (!emptyLines && topIsLineComment) found[0] = content + "\n" + found[0];
33 | else (found || (found = [])).unshift(content);
34 | topIsLineComment = true;
35 | emptyLines = 0;
36 | pos = scan - 2;
37 | break;
38 | } else if (prev == 10) {
39 | if (!sawNonWS && ++emptyLines > 1) break out;
40 | break;
41 | } else if (!sawNonWS && !isSpace(prev)) {
42 | sawNonWS = true;
43 | }
44 | }
45 | } else if (prev == 47 && text.charCodeAt(pos - 2) == 42) {
46 | for (var scan = pos - 2; scan > 1; --scan) {
47 | if (text.charCodeAt(scan - 1) == 42 && text.charCodeAt(scan - 2) == 47) {
48 | if (!onOwnLine(text, scan - 2)) break out;
49 | (found || (found = [])).unshift(text.slice(scan, pos - 2));
50 | topIsLineComment = false;
51 | emptyLines = 0;
52 | break;
53 | }
54 | }
55 | pos = scan - 2;
56 | } else if (isSpace(prev)) {
57 | --pos;
58 | } else {
59 | break;
60 | }
61 | }
62 | return found;
63 | };
64 |
65 | exports.commentAfter = function(text, pos) {
66 | while (pos < text.length) {
67 | var next = text.charCodeAt(pos);
68 | if (next == 47) {
69 | var after = text.charCodeAt(pos + 1), end;
70 | if (after == 47) // line comment
71 | end = text.indexOf("\n", pos + 2);
72 | else if (after == 42) // block comment
73 | end = text.indexOf("*/", pos + 2);
74 | else
75 | return;
76 | return text.slice(pos + 2, end < 0 ? text.length : end);
77 | } else if (isSpace(next)) {
78 | ++pos;
79 | }
80 | }
81 | };
82 |
83 | exports.ensureCommentsBefore = function(text, node) {
84 | if (node.hasOwnProperty("commentsBefore")) return node.commentsBefore;
85 | return node.commentsBefore = exports.commentsBefore(text, node.start);
86 | };
87 | });
88 |
--------------------------------------------------------------------------------
/lib/signal.js:
--------------------------------------------------------------------------------
1 | (function(root, mod) {
2 | if (typeof exports == "object" && typeof module == "object") // CommonJS
3 | return mod(exports);
4 | if (typeof define == "function" && define.amd) // AMD
5 | return define(["exports"], mod);
6 | mod((root.tern || (root.tern = {})).signal = {}); // Plain browser env
7 | })(this, function(exports) {
8 |
9 | function on(type, f) {
10 | var handlers = this._handlers || (this._handlers = Object.create(null));
11 | (handlers[type] || (handlers[type] = [])).push(f);
12 | }
13 |
14 | function off(type, f) {
15 | var arr = this._handlers && this._handlers[type];
16 | if (arr) for (var i = 0; i < arr.length; ++i)
17 | if (arr[i] == f) { arr.splice(i, 1); break; }
18 | }
19 |
20 | var noHandlers = [];
21 | function getHandlers(emitter, type) {
22 | var arr = emitter._handlers && emitter._handlers[type];
23 | return arr && arr.length ? arr.slice() : noHandlers;
24 | }
25 |
26 | function signal(type, a1, a2, a3, a4) {
27 | var arr = getHandlers(this, type);
28 | for (var i = 0; i < arr.length; ++i) arr[i].call(this, a1, a2, a3, a4);
29 | }
30 |
31 | function signalReturnFirst(type, a1, a2, a3, a4) {
32 | var arr = getHandlers(this, type);
33 | for (var i = 0; i < arr.length; ++i) {
34 | var result = arr[i].call(this, a1, a2, a3, a4);
35 | if (result) return result;
36 | }
37 | }
38 |
39 | function hasHandler(type) {
40 | var arr = this._handlers && this._handlers[type];
41 | return arr && arr.length > 0 && arr;
42 | }
43 |
44 | exports.mixin = function(obj) {
45 | obj.on = on; obj.off = off;
46 | obj.signal = signal;
47 | obj.signalReturnFirst = signalReturnFirst;
48 | obj.hasHandler = hasHandler;
49 | return obj;
50 | };
51 | });
52 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tern",
3 | "license": "MIT",
4 | "version": "0.24.3",
5 | "author": "Marijn Haverbeke ",
6 | "description": "A JavaScript code analyzer for deep, cross-editor language support",
7 | "main": "lib/tern.js",
8 | "bin": "./bin/tern",
9 | "repository": {
10 | "type": "git",
11 | "url": "git://github.com/ternjs/tern.git"
12 | },
13 | "scripts": {
14 | "test": "node ./bin/test"
15 | },
16 | "dependencies": {
17 | "acorn": "^6.0.0",
18 | "acorn-walk": "^6.0.0",
19 | "acorn-loose": "^6.0.0",
20 | "enhanced-resolve": "^2.2.2",
21 | "glob": "^7.1.1",
22 | "minimatch": "^3.0.3",
23 | "resolve-from": "2.0.0"
24 | },
25 | "devDependencies": {
26 | "codemirror": "git://github.com/codemirror/CodeMirror.git"
27 | },
28 | "blint": {
29 | "allowedGlobals": [
30 | "tern",
31 | "acorn",
32 | "define",
33 | "clearTimeout",
34 | "setTimeout",
35 | "__dirname",
36 | "global",
37 | "process"
38 | ]
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/plugin/commonjs.js:
--------------------------------------------------------------------------------
1 | (function(mod) {
2 | if (typeof exports == "object" && typeof module == "object") // CommonJS
3 | return mod(require("../lib/infer"), require("../lib/tern"), require("./modules"));
4 | if (typeof define == "function" && define.amd) // AMD
5 | return define(["../lib/infer", "../lib/tern", "./modules"], mod);
6 | mod(tern, tern);
7 | })(function(infer, tern) {
8 | "use strict";
9 |
10 | var WG_DEFAULT_EXPORT = 95;
11 |
12 | function initScope(scope) {
13 | var defs = infer.cx().definitions.commonjs;
14 | defs.require.propagate(scope.defProp("require"));
15 | var module = new infer.Obj(defs.Module.getProp("prototype").getType());
16 | module.propagate(scope.defProp("module"));
17 | var exports = new infer.Obj(true);
18 | module.origin = exports.origin = scope.origin;
19 | module.originNode = exports.originNode = scope.originNode;
20 | exports.propagate(scope.defProp("exports"));
21 | var moduleExports = scope.exports = module.defProp("exports");
22 | exports.propagate(moduleExports, WG_DEFAULT_EXPORT);
23 | }
24 |
25 | infer.registerFunction("require", function(_self, _args, argNodes) {
26 | if (!argNodes || !argNodes.length || argNodes[0].type != "Literal" || typeof argNodes[0].value != "string")
27 | return infer.ANull;
28 | var cx = infer.cx(), server = cx.parent;
29 | var currentFile = argNodes[0].sourceFile.name;
30 |
31 | var name = argNodes[0].value;
32 | var resolved = server.mod.modules.resolveModule(name, currentFile);
33 | return resolved;
34 | });
35 |
36 | function isStaticRequire(node) {
37 | if (node.type != "CallExpression" || node.callee.type != "Identifier" || node.callee.name != "require") return;
38 | var arg = node.arguments[0];
39 | if (arg && arg.type == "Literal" && typeof arg.value == "string") return arg.value;
40 | }
41 |
42 | function isModuleName(node) {
43 | if (node.type != "Literal" || typeof node.value != "string") return;
44 |
45 | var call = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null,
46 | function(_, n) { return isStaticRequire(n) != null });
47 | if (call && call.node.arguments[0] == node) return node.value;
48 | }
49 |
50 | function isImport(node) {
51 | if (node.type != "Identifier") return;
52 | var decl = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, "VariableDeclarator"), name;
53 | if (!decl || decl.node.id != node) return;
54 | var init = decl.node.init;
55 | if (init && (name = isStaticRequire(init)) != null)
56 | return {name: name, prop: null};
57 | if (init && init.type == "MemberExpression" && !init.computed && (name = isStaticRequire(init.object)) != null)
58 | return {name: name, prop: init.property.name};
59 | }
60 |
61 | function hasProps(obj) {
62 | if (obj) for (var _prop in obj) return true;
63 | }
64 |
65 | tern.registerPlugin("commonjs", function(server) {
66 | server.loadPlugin("modules");
67 | server.mod.modules.on("wrapScope", initScope);
68 | server.mod.modules.on("getExports", function(file, mod) {
69 | var exports = file.scope.exports;
70 | if (exports.types.length > 1 || hasProps(exports.getObjType()))
71 | exports.propagate(mod);
72 | });
73 |
74 | server.mod.modules.modNameTests.push(isModuleName);
75 | server.mod.modules.importTests.push(isImport);
76 | server.mod.modules.completableTypes.Identifier = true;
77 | server.mod.modules.completableTypes.Literal = true;
78 |
79 | server.addDefs(defs);
80 | });
81 |
82 | var defs = {
83 | "!name": "commonjs",
84 | "!define": {
85 | require: {
86 | "!type": "fn(id: string) -> !custom:require",
87 | resolve: {
88 | "!type": "fn() -> string",
89 | "!url": "https://nodejs.org/api/globals.html#globals_require_resolve",
90 | "!doc": "Use the internal require() machinery to look up the location of a module, but rather than loading the module, just return the resolved filename."
91 | },
92 | cache: {
93 | "!url": "https://nodejs.org/api/globals.html#globals_require_cache",
94 | "!doc": "Modules are cached in this object when they are required. By deleting a key value from this object, the next require will reload the module."
95 | },
96 | extensions: {
97 | "!url": "https://nodejs.org/api/globals.html#globals_require_extensions",
98 | "!doc": "Instruct require on how to handle certain file extensions."
99 | },
100 | "!url": "https://nodejs.org/api/globals.html#globals_require",
101 | "!doc": "To require modules."
102 | },
103 | Module: {
104 | "!type": "fn()",
105 | "!url": "https://nodejs.org/api/modules.html",
106 | "!doc": "Node has a simple module loading system. In Node, files and modules are in one-to-one correspondence.",
107 | prototype: {
108 | exports: {
109 | "!type": "?",
110 | "!url": "https://nodejs.org/api/modules.html#modules_module_exports",
111 | "!doc": "The exports object is created by the Module system. Sometimes this is not acceptable, many want their module to be an instance of some class. To do this assign the desired export object to module.exports. For example suppose we were making a module called a.js"
112 | },
113 | require: {
114 | "!type": "require",
115 | "!url": "https://nodejs.org/api/modules.html#modules_module_require_id",
116 | "!doc": "The module.require method provides a way to load a module as if require() was called from the original module."
117 | },
118 | id: {
119 | "!type": "string",
120 | "!url": "https://nodejs.org/api/modules.html#modules_module_id",
121 | "!doc": "The identifier for the module. Typically this is the fully resolved filename."
122 | },
123 | filename: {
124 | "!type": "string",
125 | "!url": "https://nodejs.org/api/modules.html#modules_module_filename",
126 | "!doc": "The fully resolved filename to the module."
127 | },
128 | loaded: {
129 | "!type": "bool",
130 | "!url": "https://nodejs.org/api/modules.html#modules_module_loaded",
131 | "!doc": "Whether or not the module is done loading, or is in the process of loading."
132 | },
133 | parent: {
134 | "!type": "+Module",
135 | "!url": "https://nodejs.org/api/modules.html#modules_module_parent",
136 | "!doc": "The module that required this one."
137 | },
138 | children: {
139 | "!type": "[+Module]",
140 | "!url": "https://nodejs.org/api/modules.html#modules_module_children",
141 | "!doc": "The module objects required by this one."
142 | }
143 | }
144 | },
145 | module: {}
146 | },
147 | module: {
148 | "!type": "+Module",
149 | "!url": "https://nodejs.org/api/globals.html#globals_module",
150 | "!doc": "A reference to the current module. In particular module.exports is the same as the exports object. module isn't actually a global but rather local to each module."
151 | }
152 | };
153 | });
154 |
--------------------------------------------------------------------------------
/plugin/complete_strings.js:
--------------------------------------------------------------------------------
1 | // When enabled, this plugin will gather (short) strings in your code,
2 | // and completing when inside a string will try to complete to
3 | // previously seen strings. Takes a single option, maxLength, which
4 | // controls the maximum length of string values to gather, and
5 | // defaults to 15.
6 |
7 | (function(mod) {
8 | if (typeof exports == "object" && typeof module == "object") // CommonJS
9 | return mod(require("../lib/infer"), require("../lib/tern"), require("acorn-walk"));
10 | if (typeof define == "function" && define.amd) // AMD
11 | return define(["../lib/infer", "../lib/tern", "acorn-walk/dist/walk"], mod);
12 | mod(tern, tern, acorn.walk);
13 | })(function(infer, tern, walk) {
14 | "use strict";
15 |
16 | tern.registerPlugin("complete_strings", function(server, options) {
17 | server.mod.completeStrings = { maxLen: options && options.maxLength || 15,
18 | seen: Object.create(null) };
19 | server.on("reset", function() {
20 | server.mod.completeStrings.seen = Object.create(null);
21 | });
22 | server.on("postParse", postParse);
23 | server.on("completion", complete);
24 | });
25 |
26 | function postParse(ast) {
27 | var data = infer.cx().parent.mod.completeStrings;
28 | walk.simple(ast, {
29 | Literal: function(node) {
30 | if (typeof node.value == "string" && node.value && node.value.length < data.maxLen)
31 | data.seen[node.value] = ast.sourceFile.name;
32 | }
33 | });
34 | }
35 |
36 | function complete(file, query) {
37 | var pos = tern.resolvePos(file, query.end);
38 | var lit = infer.findExpressionAround(file.ast, null, pos, file.scope, "Literal");
39 | if (!lit || typeof lit.node.value != "string") return;
40 | var before = lit.node.value.slice(0, pos - lit.node.start - 1);
41 | var matches = [], seen = infer.cx().parent.mod.completeStrings.seen;
42 | for (var str in seen) if (str.length > before.length && str.indexOf(before) == 0) {
43 | if (query.types || query.docs || query.urls || query.origins) {
44 | var rec = {name: JSON.stringify(str), displayName: str};
45 | matches.push(rec);
46 | if (query.types) rec.type = "string";
47 | if (query.origins) rec.origin = seen[str];
48 | } else {
49 | matches.push(JSON.stringify(str));
50 | }
51 | }
52 | if (matches.length) return {
53 | start: tern.outputPos(query, file, lit.node.start),
54 | end: tern.outputPos(query, file, pos + (file.text.charAt(pos) == file.text.charAt(lit.node.start) ? 1 : 0)),
55 | isProperty: false,
56 | completions: matches
57 | };
58 | }
59 | });
60 |
--------------------------------------------------------------------------------
/plugin/es_modules.js:
--------------------------------------------------------------------------------
1 | (function(mod) {
2 | if (typeof exports == "object" && typeof module == "object") // CommonJS
3 | return mod(require("../lib/infer"), require("../lib/tern"), require("acorn-walk"), require("./modules"));
4 | if (typeof define == "function" && define.amd) // AMD
5 | return define(["../lib/infer", "../lib/tern", "acorn-walk/dist/walk", "./modules"], mod);
6 | mod(tern, tern, acorn.walk);
7 | })(function(infer, tern, walk) {
8 | "use strict";
9 |
10 | var WG_IMPORT_DEFAULT_FALLBACK = 80;
11 |
12 | function connectModule(file, out) {
13 | var modules = infer.cx().parent.mod.modules;
14 | var outObj = null;
15 | function exp(prop, type, originNode) {
16 | if (!outObj) {
17 | outObj = new infer.Obj(true);
18 | outObj.origin = file.name;
19 | outObj.originNode = file.ast;
20 | out.addType(outObj);
21 | }
22 | var propObj = outObj.defProp(prop, originNode);
23 | propObj.origin = file.name;
24 | type.propagate(propObj);
25 | }
26 |
27 | walk.simple(file.ast, {
28 | ImportDeclaration: function(node) {
29 | var input = modules.resolveModule(node.source.value, file.name);
30 | for (var i = 0; i < node.specifiers.length; i++) {
31 | var spec = node.specifiers[i];
32 | var aval = file.scope.getProp(spec.local.name);
33 | if (spec.type == "ImportNamespaceSpecifier") {
34 | input.propagate(aval);
35 | } else if (spec.type == "ImportDefaultSpecifier") {
36 | input.getProp("default").propagate(aval);
37 | input.propagate(aval, WG_IMPORT_DEFAULT_FALLBACK);
38 | } else {
39 | input.getProp(spec.imported.name).propagate(aval);
40 | }
41 | }
42 | },
43 | ExportAllDeclaration: function(node) {
44 | var input = modules.resolveModule(node.source.value, file.name);
45 | input.forAllProps(function(prop, val, local) {
46 | if (local) exp(prop, val, val.originNode);
47 | });
48 | },
49 | ExportDefaultDeclaration: function(node) {
50 | var decl = node.declaration.id || node.declaration;
51 | exp("default", infer.expressionType({node: decl, state: file.scope}), decl);
52 | },
53 | ExportNamedDeclaration: function(node) {
54 | var decl = node.declaration;
55 | if (decl) {
56 | if (decl.type == "VariableDeclaration") {
57 | for (var i = 0; i < decl.declarations.length; ++i) {
58 | var cur = decl.declarations[i];
59 | if (cur.id.type == "Identifier")
60 | exp(cur.id.name, file.scope.getProp(cur.id.name), cur.id);
61 | }
62 | } else if (decl.id){
63 | exp(decl.id.name, file.scope.getProp(decl.id.name), decl.id);
64 | }
65 | }
66 | if (node.specifiers.length) {
67 | var src = node.source ? modules.resolveModule(node.source.value, file.name) : file.scope;
68 | for (var i = 0; i < node.specifiers.length; i++) {
69 | var spec = node.specifiers[i];
70 | exp(spec.exported.name, src.getProp(spec.local.name), spec.local);
71 | }
72 | }
73 | }
74 | });
75 | }
76 |
77 | function isModuleName(node) {
78 | if (node.type != "Literal" || typeof node.value != "string") return;
79 |
80 | var decl = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, function(_, node) {
81 | return node.type == "ImportDeclaration" || /Export(All|Named)Declaration/.test(node.type);
82 | });
83 | if (!decl || decl.node.source != node) return;
84 | return node.value;
85 | }
86 |
87 | function isImport(node, pos) {
88 | if (node.type == "Identifier") {
89 | var imp = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, "ImportDeclaration");
90 | if (!imp) return;
91 | var specs = imp.node.specifiers;
92 | for (var i = 0; i < specs.length; i++) {
93 | var spec = specs[i];
94 | if (spec.local != node) continue;
95 | var result = {name: imp.node.source.value, prop: null};
96 | if (spec.type == "ImportDefaultSpecifier") result.prop = "default";
97 | else if (spec.type == "ImportSpecifier") result.prop = spec.imported.name;
98 | return result;
99 | }
100 | } else if (node.type == "ImportDeclaration" &&
101 | /^import\s+\{\s*([\w$]+\s*,\s*)*$/.test(node.sourceFile.text.slice(node.start, pos))) {
102 | return {name: node.source.value, prop: ""};
103 | }
104 | }
105 |
106 | tern.registerPlugin("es_modules", function(server) {
107 | server.loadPlugin("modules");
108 | server.mod.modules.on("getExports", connectModule);
109 | server.mod.modules.modNameTests.push(isModuleName);
110 | server.mod.modules.importTests.push(isImport);
111 | server.mod.modules.completableTypes.Identifier = true;
112 | server.mod.modules.completableTypes.Literal = true;
113 | server.mod.modules.completableTypes.ImportDeclaration = true;
114 | });
115 | });
116 |
--------------------------------------------------------------------------------
/plugin/node_resolve.js:
--------------------------------------------------------------------------------
1 | (function(mod) {
2 | if (typeof exports == "object" && typeof module == "object") // CommonJS
3 | return mod(require("../lib/infer"), require("../lib/tern"), require("./commonjs"), require);
4 | if (typeof define == "function" && define.amd) // AMD
5 | return define(["../lib/infer", "../lib/tern", "./commonjs"], mod);
6 | mod(tern, tern);
7 | })(function(infer, tern, _, require) {
8 | "use strict";
9 |
10 | function resolve(name, parentFile) {
11 | var resolved = resolveToFile(name, parentFile);
12 | return resolved && infer.cx().parent.normalizeFilename(resolved);
13 | }
14 |
15 | var findDeclaredDeps = function () {};
16 |
17 | var resolveToFile;
18 | if (require) (function() {
19 | var module_ = require("module"), path = require("path"), fs = require("fs");
20 |
21 | resolveToFile = function(name, parentFile) {
22 | var projectDir = infer.cx().parent.projectDir;
23 | var fullParent = path.resolve(projectDir, parentFile);
24 | var parentDir = path.dirname(fullParent);
25 | if (/^\.\.?\//.test(name))
26 | name = path.resolve(projectDir, parentDir, name);
27 |
28 | var parentModule = {
29 | id: fullParent,
30 | paths: module_._nodeModulePaths(parentDir).concat(module_.globalPaths)
31 | };
32 | try {
33 | return module_._resolveFilename(name, parentModule);
34 | } catch(e) {
35 | return null;
36 | }
37 | };
38 |
39 | function findPackageFile(dir) {
40 | for (;;) {
41 | try {
42 | return JSON.parse(fs.readFileSync(path.resolve(dir, "package.json")));
43 | } catch(e) {}
44 | var shorter = path.dirname(dir);
45 | if (shorter == dir) return null;
46 | dir = shorter;
47 | }
48 | }
49 |
50 | findDeclaredDeps = function(path, knownModules) {
51 | var packageFile = findPackageFile(path);
52 | if (!packageFile) return null;
53 |
54 | function add(obj) {
55 | for (var name in obj) if (!(name in knownModules)) knownModules[name] = null;
56 | }
57 | add(packageFile.dependencies);
58 | add(packageFile.devDependencies);
59 | add(packageFile.peerDependencies);
60 | };
61 |
62 | })(); else (function() {
63 | function resolvePath(base, path) {
64 | if (path[0] == "/") return path;
65 | var slash = base.lastIndexOf("/"), m;
66 | if (slash >= 0) path = base.slice(0, slash + 1) + path;
67 | while (m = /[^\/]*[^\/\.][^\/]*\/\.\.\//.exec(path))
68 | path = path.slice(0, m.index) + path.slice(m.index + m[0].length);
69 | return path.replace(/(^|[^\.])\.\//g, "$1");
70 | }
71 |
72 | resolveToFile = function(name, parentFile) {
73 | return /^\.\.?\//.test(name) ? resolvePath(parentFile, name) : name;
74 | };
75 | })();
76 |
77 | tern.registerPlugin("node_resolve", function(server) {
78 | server.loadPlugin("commonjs");
79 | server.mod.modules.resolvers.push(resolve);
80 | findDeclaredDeps(server.projectDir, server.mod.modules.knownModules);
81 | });
82 | });
83 |
--------------------------------------------------------------------------------
/plugin/webpack.js:
--------------------------------------------------------------------------------
1 | if (typeof exports != "object" || typeof module != "object")
2 | throw new Error("This plugin works only in a CommonJS environment");
3 |
4 | var infer = require("../lib/infer");
5 | var tern = require("../lib/tern");
6 | require("./commonjs");
7 | require("./es_modules");
8 |
9 | function isArray(v) {
10 | return Object.prototype.toString.call(v) == "[object Array]";
11 | }
12 |
13 | var fs = require('fs');
14 | var path = require("path");
15 | var ResolverFactory = require("enhanced-resolve").ResolverFactory;
16 | var SyncNodeJsInputFileSystem = require("enhanced-resolve/lib/SyncNodeJsInputFileSystem");
17 |
18 | function getResolver(modules, configPath) {
19 | var config = {
20 | unsafeCache: true,
21 | modules: modules || ["node_modules"],
22 | extensions: [".js", ".jsx", ".json"],
23 | aliasFields: ["browser"],
24 | mainFields: ["browser", "web", "browserify", "main"],
25 | fileSystem: new SyncNodeJsInputFileSystem()
26 | };
27 | var webpackConfig = (configPath && fs.existsSync(configPath)) ? require(configPath) : null;
28 | if (typeof webpackConfig === 'function') {
29 | webpackConfig = webpackConfig();
30 | }
31 | var resolveConfig = webpackConfig && webpackConfig.resolve;
32 | if (resolveConfig) {
33 | Object.keys(resolveConfig).forEach(function (key) {
34 | if (key === 'packageMains') {
35 | config.mainFields = resolveConfig[key];
36 | } else if (key === 'root') {
37 | var roots = resolveConfig[key];
38 | if (isArray(roots)) {
39 | config.modules = roots.concat(config.modules);
40 | } else {
41 | config.modules.unshift(roots);
42 | }
43 | } else if (key === 'fallback') {
44 | var fallback = resolveConfig[key];
45 | if (isArray(fallback)) {
46 | config.modules = config.modules.concat(fallback);
47 | } else {
48 | config.modules.push(fallback);
49 | }
50 | } else if (key === 'modules') {
51 | config.modules = config.modules.concat(resolveConfig[key]);
52 | } else {
53 | config[key] = resolveConfig[key];
54 | }
55 | });
56 | }
57 |
58 | return ResolverFactory.createResolver(config);
59 | }
60 |
61 | function resolveToFile(resolver, name, parentFile) {
62 | var projectDir = infer.cx().parent.projectDir;
63 | var fullParent = path.resolve(projectDir, parentFile);
64 | try {
65 | return resolver.resolveSync({}, path.dirname(fullParent), name);
66 | } catch(e) {
67 | console.log(e.stack);
68 | return '';
69 | }
70 | }
71 |
72 | tern.registerPlugin("webpack", function(server, options) {
73 | var configPath = options.configPath || './webpack.config.js';
74 | var modules = options.modules || ['node_modules'];
75 | configPath = path.resolve(server.options.projectDir, configPath);
76 | var resolver = getResolver(modules, configPath);
77 | server.loadPlugin("commonjs");
78 | server.loadPlugin("es_modules");
79 | server.mod.modules.resolvers.push(function (name, parentFile) {
80 | var resolved = resolveToFile(resolver, name, parentFile);
81 | return resolved && infer.cx().parent.normalizeFilename(resolved);
82 | });
83 | });
84 |
--------------------------------------------------------------------------------
/test/cases/angular/config.js:
--------------------------------------------------------------------------------
1 | angular.module('sample.config', [])
2 |
3 | .value('myConfig', {
4 | myColor: 'red',
5 | })
6 |
7 | ;
8 |
--------------------------------------------------------------------------------
/test/cases/angular/filters.js:
--------------------------------------------------------------------------------
1 | angular.module('sample.filters', [])
2 |
3 | // greet greets the named user.
4 | .filter('greet', function() {
5 | return function(s) {
6 | return 'Hello, ' + s + '!';
7 | };
8 | })
9 |
10 | .constant("someNumber", 44)
11 |
12 | ;
13 |
--------------------------------------------------------------------------------
/test/cases/angular/main.js:
--------------------------------------------------------------------------------
1 | // plugin=angular
2 | // environment=browser
3 | // environment=jquery
4 | // loadfiles=config.js, filters.js
5 |
6 | angular.module('sample', ['ngResource', 'sample.config', 'sample.filters'])
7 |
8 | .run(function($rootScope, someNumber) {
9 | someNumber; //: number
10 | $rootScope.rootName; //: string
11 | })
12 |
13 | .controller('GreetingCtrl', ['$rootScope', '$scope', 'User', 'myConfig', 'version', function($rootScope, $scope, User, myConfig, version) {
14 | $rootScope.rootName = $scope.myName = 'John';
15 | $scope.myName; //: string
16 |
17 | $scope.myConfig = myConfig; //: {myColor}
18 | $scope.myConfig; //: {myColor}
19 |
20 | $scope.version = version; //: string
21 | $scope.version; //: string
22 |
23 | User; //doc: doc for User
24 |
25 | $scope.user = User.get({login: 'sqs'});
26 | $scope.user.$promise.finally; //: fn(callback: fn()) -> Promise
27 | }])
28 |
29 | .controller('OtherCtrl', ['$scope', function($scope) {
30 | // Test that controllers' $scope objects are distinct.
31 | $scope.myName; //: ?
32 | }])
33 |
34 | .constant('version', 'v1.2.3')
35 |
36 | // doc for User
37 | .factory('User', ['$resource', function($resource) {
38 | return $resource('https://api.github.com/users/:login');
39 | }])
40 |
41 | ;
42 |
43 | angular.module('docsScopeProblemExample', [])
44 | .directive('myCustomer', function() {
45 | return {
46 | //+ bindToController, compile, controller, controllerAs, template, templateUrl, ...
47 | };
48 | }).directive('myCustomer', function() {
49 | return {
50 | t //+ template, templateNamespace, templateUrl, ...
51 | };
52 | });
53 |
54 | // Create a new object and extend it with angular.extend
55 | var extendObject = { aNumber: 2 };
56 | angular.extend(extendObject, { aString: 'baz' });
57 |
58 | extendObject.aNumber; //: number
59 | extendObject.aString; //: string
60 |
--------------------------------------------------------------------------------
/test/cases/angular_service.js:
--------------------------------------------------------------------------------
1 | // Issue #267
2 |
3 | // plugin=angular
4 | // environment=browser
5 |
6 | var foodMeApp = angular.module('foodMeApp');
7 |
8 | foodMeApp.service('cart', function Cart(localStorage, customer, $rootScope, $http, alert) {
9 | this.length = "4";
10 | });
11 |
12 | foodMeApp.controller('CheckoutController', function CheckoutController($scope, cart) {
13 | cart; //: Cart
14 | cart.length; //: string
15 | });
16 |
--------------------------------------------------------------------------------
/test/cases/arguments.js:
--------------------------------------------------------------------------------
1 | var arguments = 1; //: number
2 |
3 | (function() { return arguments.length; })(); //: number
4 |
--------------------------------------------------------------------------------
/test/cases/arithmetic_ops.js:
--------------------------------------------------------------------------------
1 |
2 | var a = '1' + 1;
3 | a; //: string
4 |
5 | var b = '1' - 1;
6 | b; //: number
7 |
8 | var c = '1' * 1;
9 | c; //: number
10 |
11 | var d = '1' / 1;
12 | d; //: number
13 |
14 | var e = '1' % 1;
15 | e; //: number
16 |
17 | var f = '1' ** 1;
18 | f; //: number
19 |
--------------------------------------------------------------------------------
/test/cases/array_holes.js:
--------------------------------------------------------------------------------
1 | var x = [,, "foo", "bar"]
2 |
3 | var [,, y, z] = x
4 |
5 | y //: string
6 | z //: string
7 |
--------------------------------------------------------------------------------
/test/cases/arrow.js:
--------------------------------------------------------------------------------
1 | let f = (a, [b]) => ({a, b})
2 |
3 | f(1, [true]) //:: {a: number, b: bool}
4 |
5 | function wrap() {
6 | return () => (this //:: {a: number}
7 | )
8 | }
9 | wrap.call({a: 10}).call({b: true}) //:: {a: number}
10 |
11 | function Obj() {
12 | this.x = true
13 | }
14 | Obj.prototype.map = function() {
15 | return [1, 2, 3].map(e => this.x)
16 | }
17 |
18 | ;(new Obj).map() //: [bool]
19 |
--------------------------------------------------------------------------------
/test/cases/async-arrow.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 |
3 | var aFetch = async () => {
4 | var res = await fetch('htts://www.google.com');
5 | var data = await res.arrayBuffer();
6 | data; //: ArrayBuffer
7 | return data;
8 | }
9 |
10 | var aParse = async () => {
11 | var tmp = await 100;
12 | tmp; //: number
13 | var arr = await aFetch();
14 | arr; //: ArrayBuffer
15 | }
16 |
17 |
18 | var bFetch = async () => {
19 | var res = await fetch('htts://www.google.com');
20 | return res.arrayBuffer();
21 | }
22 |
23 | var bParse = async () => {
24 | var arr = await bFetch();
25 | arr; //: ArrayBuffer
26 | }
27 |
28 |
29 | var cFetch = async () => {
30 | var res = await fetch('htts://www.google.com');
31 | return res.arrayBuffer();
32 | }
33 |
34 | var cParse = async () => {
35 | var pr = cFetch();
36 | pr; //: Promise
37 | pr.then(function (arr) {
38 | arr; //: ArrayBuffer
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/test/cases/async.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 |
3 | async function aFetch () {
4 | var res = await fetch('htts://www.google.com');
5 | var data = await res.arrayBuffer();
6 | data; //: ArrayBuffer
7 | return data;
8 | }
9 |
10 | async function aParse () {
11 | var tmp = await 100;
12 | tmp; //: number
13 | var arr = await aFetch();
14 | arr; //: ArrayBuffer
15 | }
16 |
17 |
18 | async function bFetch () {
19 | var res = await fetch('htts://www.google.com');
20 | return res.arrayBuffer();
21 | }
22 |
23 | async function bParse () {
24 | var arr = await bFetch();
25 | arr; //: ArrayBuffer
26 | }
27 |
28 |
29 | async function cFetch () {
30 | var res = await fetch('htts://www.google.com');
31 | return res.arrayBuffer();
32 | }
33 |
34 | async function cParse () {
35 | var pr = cFetch();
36 | pr; //: Promise
37 | pr.then(function (arr) {
38 | arr; //: ArrayBuffer
39 | });
40 | }
41 |
--------------------------------------------------------------------------------
/test/cases/async_for_of.js:
--------------------------------------------------------------------------------
1 | var myIter = {
2 | [Symbol.asyncIterator]() {
3 | return {
4 | next() {
5 | return Promise.resolve({value: {a: 1, b: true}, done: false})
6 | }
7 | }
8 | }
9 | }
10 |
11 | async function run () {
12 |
13 | for await (var hello of myIter) {
14 | hello //:: {a: number, b: bool}
15 | }
16 |
17 | for await (var {a, b} of myIter) {
18 | a //: number
19 | b //: bool
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/test/cases/async_generator.js:
--------------------------------------------------------------------------------
1 | async function scope () {
2 | async function * myGen () {
3 | yield {c: 1};
4 | return {c: 2};
5 | }
6 |
7 | var iter = myGen();
8 |
9 | for await (const item of iter) {
10 | item; //:: {c: number}
11 | }
12 | }
--------------------------------------------------------------------------------
/test/cases/autothis.js:
--------------------------------------------------------------------------------
1 | function Bar() { this.prop = 10; }
2 | Bar.prototype.hallo = function() {
3 | this; //: Bar
4 | this.prop; //: number
5 | };
6 |
7 | Bar.prototype.fn2 = function() {
8 | this; //: Date
9 | };
10 |
11 | Date.prototype.fn2 = Bar.prototype.fn2;
12 | new Date().fn2();
13 |
--------------------------------------------------------------------------------
/test/cases/bind.js:
--------------------------------------------------------------------------------
1 | function f(a, b, c, d) { return a + b + c + d; }
2 | var g = f.bind(null, 1, 2);
3 |
4 | g(2, 3); //: number
5 | g; //: fn(c: number, d: number) -> number
6 |
7 | function h(a) { return {a: a, th: this}; }
8 | var i = h.bind({str: "foo"}, 2);
9 |
10 | i.call({x: 1}); //:: {a: number, th: {str: string}}
11 |
12 | var o = {i: i};
13 | o.i(); //:: {a: number, th: {str: string}}
14 |
15 | function j() { return this; }
16 | var k = j.bind({a: true});
17 |
18 | k.call({b: false});
19 | k(); //:: {a: bool}
20 |
--------------------------------------------------------------------------------
/test/cases/block_scope.js:
--------------------------------------------------------------------------------
1 | function x(a) {
2 | {
3 | let a = 4
4 | let b = 10
5 | var c = true
6 | a; //: number
7 | b; //: number
8 | c; //: bool
9 | }
10 | a; //: string
11 | b; //: ?
12 | c; //: bool
13 | }
14 |
15 | x("hello")
16 |
--------------------------------------------------------------------------------
/test/cases/blowup.js:
--------------------------------------------------------------------------------
1 | var Ext = Ext || {};
2 | Ext.extend = function(subclass, superclass) {
3 | superclass = subclass;
4 | subclass = function() { superclass.apply(this, arguments); };
5 |
6 | var F = function() {};
7 | F.prototype = superclass.prototype;
8 | subclass.prototype = new F();
9 |
10 | subclass.extend = function(o) { return Ext.extend(subclass, o); };
11 | };
12 |
13 | var Ext = Ext || {};
14 | Ext.extend = function(subclass, superclass) {
15 | superclass = subclass;
16 | subclass = function() { superclass.apply(this, arguments); };
17 |
18 | var F = function() {};
19 | F.prototype = superclass.prototype;
20 | subclass.prototype = new F();
21 |
22 | subclass.extend = function(o) { return Ext.extend(subclass, o); };
23 | };
24 |
--------------------------------------------------------------------------------
/test/cases/browser.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 |
3 | window.document.body; //: Element
4 |
5 | var newElt = document.createElement("div"); //: Element
6 |
7 | newElt.style.border; //: string
8 |
9 | var e_which;
10 | window.addEventListener("mousemove", function(e) { e_which = e.which; });
11 | e_which; //: number
12 |
13 | console.; //+ assert, clear, count, debug, dir, error, group, groupCollapsed, groupEnd, info, log, table, time, timeEnd, trace, warn
14 |
15 | var u = new URL();
16 | u.; //+ hash, host, hostname, href, origin, password, pathname, port, protocol, search, searchParams, username
17 | u.origin; //: string
18 |
19 | var sq = u.searchParams;
20 | sq; //: URLSearchParams
21 | sq.; //+ append, delete, entries, get, getAll, has, keys, set, sort, toString, values
22 | sq.keys().next().value; //: string
--------------------------------------------------------------------------------
/test/cases/builtins.js:
--------------------------------------------------------------------------------
1 | var x = Math.PI; //: number
2 | Math.cos(x); //: number
3 |
4 | var a = [1, 2, 3]; //: [number]
5 | a.slice(2); //: [number]
6 | a.pop(); //: number
7 |
8 | ["x"].concat(["hi"]); //: [string]
9 |
10 | [true, false, true].filter(function(x){return x;}); //: [bool]
11 |
12 | [].map(function() {return "x";}); //: [string]
13 |
14 | [].reduce(function(a, b) { return a - 2; }, 0); //: number
15 |
16 | Math.cos.call(null, 10); //: number
17 |
18 | (10).toFixed; //: fn(digits: number) -> string
19 |
20 | "foo bar baz".split(" "); //: [string]
21 |
22 | toString; //: fn() -> string
23 |
24 | new Date; //: Date
25 |
26 | var num = new Number(1);
27 | num; //: Number
28 |
29 | "foo".toString(); //: string
30 |
31 | Array.prototype.slice.call([1, 2, 3], 1); //: [number]
32 |
33 | Array.prototype.slice.apply([1, 2, 3], [1]); //: [number]
34 |
35 | String.prototype.indexOf.bind("abcde", "a"); //: fn(from?: number) -> number
36 |
--------------------------------------------------------------------------------
/test/cases/catch_error.js:
--------------------------------------------------------------------------------
1 | try {
2 | foo();
3 | } catch(e) {
4 | e.message; //doc: A human-readable description of the error.
5 | }
6 | e //: ?
7 |
--------------------------------------------------------------------------------
/test/cases/cautiouspropagation.js:
--------------------------------------------------------------------------------
1 | var grabbag = {};
2 | grabbag[foo()] = "hi";
3 | grabbag[bar()] = {abc: 10};
4 | grabbag[baz()] = [1, 2, 3];
5 | var inner = 55 || grabbag[quux()];
6 | inner; //: number
7 |
8 | var simple = {};
9 | simple[foo()] = "a";
10 | simple[bar()] = "b";
11 | simple[baz()] = "c";
12 | simple[quux()]; //: string
13 |
--------------------------------------------------------------------------------
/test/cases/class.js:
--------------------------------------------------------------------------------
1 | class Point2 {
2 | constructor(x, y) { this.x = x; this.y = y }
3 | plus(pt) {
4 | this //: Point2
5 | pt //: Point2
6 | return new Point2(this.x + pt.x, this.y + pt.y)
7 | }
8 | get xx() { return this.x }
9 | quux() { return 1 }
10 | static origin() { return new Point2(0, 0) }
11 | }
12 |
13 | class Point4 extends Point3 {
14 | constructor(x, y, z, u) { super(x, y, z); this.u = u }
15 | argh() { return 2 }
16 | }
17 |
18 | var Point3 = class extends Point2 {
19 | constructor(x, y, z) { super(x, y); this.z = z }
20 | foobar() { return true }
21 | }
22 |
23 | var p1 = new Point2(1, 2)
24 | p1.x //: number
25 | p1 //: Point2
26 | var p2 = Point2.origin()
27 | p2 //: Point2
28 | p1.plus(p2) //: Point2
29 | p1.foobar() //: ?
30 | p1.xx //: number
31 |
32 | var p3 = new Point3(0, 0, 5)
33 | p3 //: Point3
34 | p3.quux() //: number
35 | p3.foobar() //: bool
36 |
37 | var p4 = new Point4(1, 2, 3, 4)
38 | p4 //: Point4
39 | p4.argh() //: number
40 | p4.foobar() //: bool
41 | p4.quux() //: number
42 |
--------------------------------------------------------------------------------
/test/cases/complete_strings.js:
--------------------------------------------------------------------------------
1 | // plugin=complete_strings
2 | // blank-comments=true
3 |
4 | if (x == "foobar") {
5 | apparently(x == "f
6 | //<+ "foobar"
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/computedprop.js:
--------------------------------------------------------------------------------
1 | var x = {};
2 | x[foo()] = {a: 10, b: 20};
3 | x.bar.a; //: number
4 | x.bar. //+? a, b
5 |
6 | var obj = {a: "bar", b: "baz"};
7 | obj[foo()]; //:? string
8 |
--------------------------------------------------------------------------------
/test/cases/contextcomplete.js:
--------------------------------------------------------------------------------
1 | function whoAmI(a, i) {
2 | a.splice(i, 1);
3 | a.c //+? concat, copyWithin
4 | }
5 |
--------------------------------------------------------------------------------
/test/cases/copyprops.js:
--------------------------------------------------------------------------------
1 | function buildCopy(o) {
2 | var oo = {};
3 | for (var prop in o) oo[prop] = o[prop];
4 | return oo;
5 | }
6 |
7 | buildCopy({xx: 10, yy: 20}); //:: {xx: number, yy: number}
8 |
--------------------------------------------------------------------------------
/test/cases/ctorpattern.js:
--------------------------------------------------------------------------------
1 | // Verify that the binding of `this` to the top scope is overridden by
2 | // the binding to an instance.
3 |
4 | function Ctor() {
5 | if (!(this instanceof Ctor)) return new Ctor();
6 | this.foo = 20;
7 | }
8 |
9 | Ctor().foo; //: number
10 | foo; //: ?
11 |
--------------------------------------------------------------------------------
/test/cases/def_type_string.js:
--------------------------------------------------------------------------------
1 | // environment=string
2 |
3 | foo; //: string
4 |
--------------------------------------------------------------------------------
/test/cases/defineProperty.js:
--------------------------------------------------------------------------------
1 | var o = {};
2 |
3 | // Docstring for prop1
4 | Object.defineProperty(o, "prop1", {
5 | get: function() { return "hi"; }
6 | });
7 |
8 | Object.defineProperty(o, "prop2", {
9 | value: 100
10 | });
11 |
12 | o.prop1; //: string
13 | o.prop2; //: number
14 |
15 | o.prop1; //doc: Docstring for prop1
16 |
17 | var o2 = {};
18 |
19 | Object.defineProperties(o2, {
20 | prop1: {get: function() { return 2; }},
21 | prop2: {value: true}
22 | });
23 |
24 | o2.prop1; //: number
25 | o2.prop2; //: bool
26 |
--------------------------------------------------------------------------------
/test/cases/defs/span.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "a/b.js",
3 | "iHaveASpan": {
4 | "!type": "fn()",
5 | "!span": "40[3:2]-60[3:22]"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/defs/string.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "a/b.js",
3 | "foo": {
4 | "!type": "string",
5 | "!span": "1[1:1]-2[2:2]"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/destructure.js:
--------------------------------------------------------------------------------
1 | let [a] = [1, 2]
2 | a //: number
3 |
4 | let {c, d} = {c: "hello", d: true}
5 | c //: string
6 | d //: bool
7 |
8 | function foo([e], {f=1}, {g}, ...h) {
9 | e //: bool
10 | f //: number
11 | g //: string
12 | h //: [number]
13 | }
14 | // Check for argument leakage
15 | e //: ?
16 | g //: ?
17 |
18 | foo([false], blah(), {g: "hello"}, 20)
19 |
20 | let i, j
21 | ;({i, j, k: [l, ...m]} = {i: 1, j: false, k: ["a", "b"]})
22 |
23 | i //: number
24 | j //: bool
25 | l //: string
26 | m //: [string]
27 |
28 | var out = {}
29 | ;[out.prop, out.prop2] = [55, true]
30 | out //:: {prop2: bool, prop: number}
31 |
32 | var [n, o] = ["a", false]
33 | n //: string
34 | o //: bool
35 |
--------------------------------------------------------------------------------
/test/cases/docstrings.js:
--------------------------------------------------------------------------------
1 | Date; //doc: Creates JavaScript Date instances which let you work with dates and times.
2 | new Date; //doc: Creates JavaScript Date instances which let you work with dates and times.
3 |
4 | var myalias = Date;
5 |
6 | myalias; //doc: Creates JavaScript Date instances which let you work with dates and times.
7 |
8 | // This is variable foo.
9 | var foo = 10;
10 |
11 | foo; //doc: This is variable foo.
12 |
13 | // This function returns a monkey.
14 | function makeMonkey() { return "monkey"; }
15 |
16 | makeMonkey; //doc: This function returns a monkey.
17 |
18 | var monkeyAlias = makeMonkey;
19 |
20 | monkeyAlias; //doc: This function returns a monkey.
21 |
22 | // This is an irrelevant comment.
23 |
24 |
25 | // This describes abc.
26 | var abc = 20;
27 |
28 | abc; //doc: This describes abc.
29 |
30 | // Quux is a thing.
31 | // Two lines.
32 | function Quux() {}
33 |
34 | Quux; //doc+: Quux is a thing.\nTwo lines.
35 |
36 | /*
37 | * Extra bogus
38 | * whitespace is also stripped.
39 | */
40 | var baz = "hi";
41 |
42 | baz; //doc: Extra bogus whitespace is also stripped.
43 |
44 | /* starry format
45 | * with first line text
46 | */
47 | var oy = 1;
48 |
49 | oy; //doc: starry format with first line text
50 |
51 | // Block of text
52 | // With some
53 | // * indented
54 | // * pieces
55 | //
56 | // And a blank line
57 | var arr = 6;
58 |
59 | arr; //doc+: Block of text\nWith some\n * indented\n * pieces\n\nAnd a blank line
60 |
61 | // Split off sentences after the first 100 characters. If our pattern
62 | // happens to match. Here we are at about 90 so this one goes over and
63 | // would be removed.
64 | var aha = "";
65 |
66 | aha; //doc: Split off sentences after the first 100 characters. If our pattern happens to match.
67 |
68 | // Also ignore JSDoc-y stuff
69 | // @type {zoink}
70 | var xyzzy = false;
71 |
72 | xyzzy; //doc: Also ignore JSDoc-y stuff
73 |
74 | var o = {
75 | // Get the name.
76 | getName: function() { return this.name; },
77 | // The name
78 | name: "Harold",
79 | // A computed property
80 | [1 + 1]: "OK",
81 | // A string property
82 | 'bar': 4
83 | };
84 |
85 | // The string "foo".
86 | o.foo = "foo";
87 |
88 | o.getName; //doc: Get the name.
89 | o.name; //doc: The name
90 | o.foo; //doc: The string "foo".
91 | o.bar //doc: A string property
92 |
93 | class C {
94 | // The method
95 | method() { return 10 }
96 | // The something
97 | get something() { return 20 }
98 | }
99 |
100 | var c = new C
101 |
102 | c.method //doc: The method
103 | c.something //doc: The something
104 |
--------------------------------------------------------------------------------
/test/cases/effects.js:
--------------------------------------------------------------------------------
1 | ["foo", "bar"].map(function(s) { return s.charCodeAt(0); }); //: [number]
2 |
3 | var b = [];
4 | b.push(true);
5 | b; //: [bool]
6 |
7 | var c = [];
8 | c.push("hi");
9 | c.push(10);
10 | c; //: [string|number]
11 |
12 | var d;
13 | function setD(a) { d = a; }
14 | setD.call(null, 55);
15 | d; //: number
16 |
--------------------------------------------------------------------------------
/test/cases/empty_overridden_prop.js:
--------------------------------------------------------------------------------
1 | function Class() {}
2 | Class.prototype.hello = "string";
3 |
4 | var c = new Class;
5 | c.hello = nobodyKnows();
6 |
7 | c.hello; //: string
8 |
--------------------------------------------------------------------------------
/test/cases/es6-features.js:
--------------------------------------------------------------------------------
1 | class Foo {
2 | constructor(a = 10, ...b) {
3 | this.a = a
4 | this.b = b
5 | }
6 |
7 | method() { return this.a + this.b }
8 |
9 | get x() { return `template${this.a}` }
10 | }
11 |
12 | let x = 1
13 |
14 | const y = {
15 | func() { return 10 },
16 | get b() { return false },
17 | ["foo" + "bar"]: 800
18 | }
19 |
20 | let it = function*(n) {
21 | for (let i = 0; i < n; i++) yield n
22 | }
23 |
24 | console.log([for (a of [1, 2, ...it(10)]) a * 2])
25 |
26 | let [a, b] = [1, 2];
27 |
28 | let x = ([a], {b}) => a + b
29 |
30 | let [e1,,e3] = ["5", false, 6]
31 |
32 | const obj = {
33 | hi: 'hello'
34 | };
35 |
36 | const newObj = {
37 | hi,
38 | ...o //+
39 | }
40 | const {
41 | hi,
42 | ...o //+
43 | } = obj //+ obj
44 |
--------------------------------------------------------------------------------
/test/cases/es_modules/blah.js:
--------------------------------------------------------------------------------
1 | export var a = 10
2 | export let b = "ten", c = true
3 | export function d() { return 10 }
4 |
--------------------------------------------------------------------------------
/test/cases/es_modules/class.js:
--------------------------------------------------------------------------------
1 | export default class {
2 | methodA() {
3 | }
4 | };
--------------------------------------------------------------------------------
/test/cases/es_modules/foo.js:
--------------------------------------------------------------------------------
1 | export default 22
2 |
3 | export function hello() { return true }
4 |
5 | export var heythere = 100
6 |
--------------------------------------------------------------------------------
/test/cases/es_modules/func.js:
--------------------------------------------------------------------------------
1 | export default function () { return true; }
--------------------------------------------------------------------------------
/test/cases/es_modules/main.js:
--------------------------------------------------------------------------------
1 | // plugin=node
2 | // plugin=es_modules
3 |
4 | import foo from "./foo"
5 | foo //: number
6 | import {hello as holle // bool
10 |
11 | import {//+ isatty
12 | } from "tty"
13 |
14 | import * as blah // number}
17 |
18 | import * as reexp from "./reexp"
19 | reexp //:: {a: number, b: bool}
20 |
21 | import "./b" //+ "./blah"
22 |
23 | import C from "./class"
24 |
25 | (new C()). //+ methodA
26 |
27 | import f from "./func"
28 |
29 | f //: fn() -> bool
30 |
31 | import o from "./obj"
32 |
33 | o.propA //: number
34 | o.propB //: string
35 |
--------------------------------------------------------------------------------
/test/cases/es_modules/obj.js:
--------------------------------------------------------------------------------
1 | export default {propA: 1, propB: "str"}
--------------------------------------------------------------------------------
/test/cases/es_modules/reexp.js:
--------------------------------------------------------------------------------
1 | export {a, c as b} from "./blah"
2 |
--------------------------------------------------------------------------------
/test/cases/extends.js:
--------------------------------------------------------------------------------
1 | // Follows the pattern CoffeeScript uses to define classes.
2 |
3 | var __extends = function(child, parent) {
4 | for (var key in parent) { child[key] = parent[key]; }
5 | function ctor() { this.constructor = child; }
6 | ctor.prototype = parent.prototype;
7 | child.prototype = new ctor();
8 | };
9 |
10 | var Top = (function() {
11 | function Top() {}
12 | Top.prototype.topMethod = function() {return "hey";};
13 | Top.topStatic = 20;
14 | return Top;
15 | })();
16 |
17 | var SubOne = (function(_super) {
18 | function SubOne(arg) { this.argOne = arg; }
19 | __extends(SubOne, _super);
20 | SubOne.prototype.methodOne = function() {return 11;};
21 | return SubOne;
22 | })(Top);
23 |
24 | var SubTwo = (function(_super) {
25 | function SubTwo(arg) { this.argTwo = arg; }
26 | __extends(SubTwo, _super);
27 | SubTwo.prototype.methodTwo = function() {return null;};
28 | return SubTwo;
29 | })(Top);
30 |
31 | var SubEleven = (function(_super) {
32 | function SubEleven(arg) { SubOne.call(this, arg); }
33 | __extends(SubEleven, SubOne);
34 | SubEleven.prototype.methodEleven = function() {return "blah";};
35 | return SubEleven;
36 | })(SubOne);
37 |
38 | var top = new Top, one = new SubOne(true), two = new SubTwo(false), elf = new SubEleven(true);
39 |
40 | one.topMethod; //: fn() -> string
41 |
42 | one.methodOne; //: fn() -> number
43 |
44 | one.argOne; //: bool
45 |
46 | one.argTwo; //: ?
47 |
48 | two.argTwo; //: bool
49 |
50 | one.methodTwo; //: ?
51 |
52 | one.methodEleven; //: ?
53 |
54 | SubEleven.topStatic; //: number
55 |
56 | elf.methodOne; //: fn() -> number
57 |
58 | elf.methodEleven(); //: string
59 |
60 | two.methodEleven; //: ?
61 |
--------------------------------------------------------------------------------
/test/cases/fetch.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 |
3 | var f = fetch('htts://www.google.com');
4 |
5 | f.then(function (resp) {
6 | resp; //: Response
7 |
8 | resp.; //+ arrayBuffer, blob, bodyUsed, clone, error, formData, headers, json, ok, redirect, status, statusText, text, type, url
9 |
10 | resp.arrayBuffer().then(function (ab) {
11 | ab; //: ArrayBuffer
12 | });
13 | resp.blob().then(function (b) {
14 | b; //: Blob
15 | });
16 | resp.json().then(function (j) {
17 | j; //: ?
18 | });
19 | resp.text().then(function (t) {
20 | t; //: string
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/cases/finddef.js:
--------------------------------------------------------------------------------
1 | function blah() {}
2 |
3 | var jaja = 40;
4 |
5 | var obj = {
6 | prop1: 10,
7 | prop2: function(foo) {}
8 | };
9 |
10 | obj.prop3 = "hi";
11 |
12 | blah; //loc: 1, 9
13 | jaja; //loc: 3, 4
14 | obj; //loc: 5, 4
15 | obj.prop1; //loc: 6, 2
16 | obj.prop2; //loc: 7, 2
17 | obj.prop3; //loc: 10, 4
18 |
19 | function hide() { return obj.prop2; }
20 |
21 | hide(); //loc: 7, 9
22 |
23 | function another(arg) {
24 | var local = 1;
25 | arg; // 23, 17
26 | local; //loc: 24, 6
27 | }
28 |
29 | class foo {
30 | bar // string
15 | this.foo; //: fn() -> number
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/test/cases/infinite-expansion.js:
--------------------------------------------------------------------------------
1 | // Issue #16
2 |
3 | var f = function(n) {
4 | n.prototype = {}; // Make this count as a type construction function
5 | f(n()); // Push an IsCallee constraint from the body
6 | };
7 | f(f);
8 |
9 | // Create a self-referential type
10 | var x = [x];
11 |
12 | // Force analysis
13 | x[0]; //: [?]
14 |
15 | function goop(n) {
16 | n.prototype = {};
17 | return function(f){f(1);};
18 | };
19 | goop(1)(goop);
20 |
--------------------------------------------------------------------------------
/test/cases/jquery_event.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 | // environment=jquery
3 |
4 | $("#foo").blur().click(function(e) {
5 | e; //: jQuery.Event
6 | e.pageX; //: number
7 | });
8 |
--------------------------------------------------------------------------------
/test/cases/jsdoc.js:
--------------------------------------------------------------------------------
1 | /** @type {Date} */
2 | var a = getSomething();
3 | a; //: Date
4 |
5 | a.getTime; //: fn() -> number
6 |
7 | /** @type {{x: Integer, y: [String]}} */
8 | var c = somethingElse();
9 | c; //:: {x: number, y: [string]}
10 |
11 | /**
12 | * This is a function
13 | * @return {[Number]}
14 | * @param {Number} a
15 | * @param {String} b
16 | */
17 | function foo(a, b) { return hohoho(); }
18 | foo; //: fn(a: number, b: string) -> [number]
19 |
20 | /** @this Date */
21 | var abc = function() {
22 | this; //: Date
23 | };
24 |
25 | /** @this Abc */
26 | var Abc = function() {
27 | this; //: Abc
28 | };
29 |
30 | /** @class */
31 | var AbcCls = function() {
32 | this; //: AbcCls
33 | };
34 |
35 | /** @constructor */
36 | var AbcCtor = function() {
37 | this; //: AbcCtor
38 | };
39 |
40 | /**
41 | * This is also a function
42 | * @returns {string}
43 | * @arg {Number} a
44 | */
45 | var bar = function(a, b) { return goop(); };
46 | bar(gulp(), 10);
47 | bar; //: fn(a: number, b: number) -> string
48 |
49 | var o = {
50 | /** @type {String} */
51 | prop1: mystery(),
52 |
53 | /** @returns {Number} */
54 | prop2: function() { return anything(); }
55 | };
56 |
57 | /** @returns {String} */
58 | o.prop3 = function() { return something(); };
59 |
60 | o.prop1; //: string
61 | o.prop2; //: fn() -> number
62 | o.prop3; //: fn() -> string
63 |
64 | /** @type {Array.} */
65 | var closureArray = anotherThing();
66 | closureArray[1]; //: string
67 |
68 | /** @type {Object.} */
69 | var closureMap = yetAnotherThing();
70 | closureMap[1]; //: bool
71 |
72 | /** @param {Number=} a */
73 | function takesOpt(a) { console.log(a || 20); }
74 |
75 | takesOpt; //: fn(a?: number)
76 |
77 | /** @typedef {Array.} Bitset */
78 |
79 | /**
80 | * @typedef {Object} MyType
81 | * @property {boolean} one - Property one
82 | * @property {integer} two - And two
83 | */
84 |
85 | someNonDeclarationStatement();
86 |
87 | /** @type {Bitset} */
88 | var myBitset = getABitset();
89 |
90 | myBitset; //: [bool]
91 |
92 | /** @type {MyType} */
93 | var myObj;
94 |
95 | myObj.one //: bool
96 | myObj.two //: number
97 | ({}).one //: ?
98 |
99 | function NonAscïį() { this.length = "hi"; }
100 |
101 | /** @type {NonAscïį} */
102 | var inst;
103 |
104 | inst.length; //: string
105 |
106 | /** @type {bogus.Type} */
107 | var bogus = abcdef();
108 |
109 | bogus; //: bogus.Type
110 |
111 | /** @type {bogus.Overridden} */
112 | var again = 10;
113 |
114 | again; //: number
115 |
116 | /**
117 | * @return {bogus.Retval}
118 | * @param {bogus.Arg} a
119 | */
120 | function functionBogus(a) { return hohoho(); }
121 |
122 | functionBogus; //: fn(a: bogus.Arg) -> bogus.Retval
123 |
124 | /** @type {string|number} */
125 | var stringOrNumber;
126 |
127 | stringOrNumber; //: string|number
128 |
129 | /**
130 | * @param {string|null} a
131 | * @return {Array.}
132 | */
133 | function unionFunction(a) { return argh(); }
134 |
135 | unionFunction; //: fn(a: string) -> [Foo|number]
136 |
137 | /**
138 | * @returns {string}
139 | */
140 | function ui() {}
141 |
142 | ui(); //: string
143 |
144 | /**
145 | * @param {?string} [somebody=John Doe] - Somebody's name.
146 | */
147 | function sayHello(somebody) {
148 | somebody; //: string
149 | }
150 |
151 | /**
152 | * Testing jsdoc with properties for an object
153 | * @param {!Object} employee - The employee who is responsible for the project.
154 | * @param {string} employee.name - The name of the employee.
155 | * @param {string} employee.department - The employee's department.
156 | */
157 | function paramProperties(employee) {
158 | employee; //:: {department: string, name: string}
159 | }
160 |
161 | /**
162 | * Testing jsdoc with properties for objects in an array
163 | * @param {Object[]} employees - The employees who are responsible for the project.
164 | * @param {string} employees[].name - The name of an employee.
165 | * @param {string} employees[].department - The employee's department.
166 | */
167 | function arrayParamProperties(employees) {
168 | employees; //:: [{department: string, name: string}]
169 | }
170 |
--------------------------------------------------------------------------------
/test/cases/map.js:
--------------------------------------------------------------------------------
1 | let map = new Map
2 |
3 | map.set(55, "hello")
4 | map.get(55) //: string
5 |
6 | for (let val of map.values())
7 | val //: string
8 |
9 | for (let key of map.keys())
10 | key //: number
11 |
12 | for (let [key, value] of map) {
13 | key //: number
14 | value //: string
15 | }
16 | for (let pair of map) {
17 | pair //: [number, string]
18 | ;[key, value] = pair
19 | key //: number
20 | value //: string
21 | }
22 |
23 | map.forEach(function(val, key) {
24 | val //: string
25 | key //: number
26 | })
27 |
--------------------------------------------------------------------------------
/test/cases/merge.js:
--------------------------------------------------------------------------------
1 | function sum(a) {
2 | return a.x + 20;
3 | }
4 |
5 | sum({x: 10, y: 20});
6 | sum({x: 10, y: 20});
7 |
8 | sum; //:: fn(a: {x: number, y: number}) -> number
9 |
--------------------------------------------------------------------------------
/test/cases/mixin.js:
--------------------------------------------------------------------------------
1 | function Class() {}
2 | Class.prototype = mixin({
3 | // M3
4 | m3: function() {}
5 | })
6 |
7 | function mixin(obj) {
8 | obj.m1 = m1
9 | obj.m2 = m2
10 | return obj
11 | }
12 |
13 | // M1
14 | function m1() {}
15 | // M2
16 | function m2() {}
17 |
18 | function OtherClass() {}
19 | OtherClass.prototype = mixin({
20 | // M4
21 | m4: function() {}
22 | })
23 |
24 | let c = new Class
25 |
26 | c.m1 //doc: M1
27 | c.m2 //doc: M2
28 | c.m3 //doc: M3
29 | c.m4 //: ?
30 |
31 | let oc = new OtherClass
32 |
33 | oc.m1 //doc: M1
34 | oc.m3 //: ?
35 | oc.m4 //doc: M4
36 |
37 | mixin(new Date) //: Date
38 | mixin("foo") //: string
39 |
--------------------------------------------------------------------------------
/test/cases/navigator.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 |
3 | navigator; //: navigator
4 |
5 | navigator.onLine; //: bool
6 |
7 | navigator.permissions.query({name: 'geolocation'}).then(function (status) {
8 | status; //: PermissionStatus
9 | })
10 |
--------------------------------------------------------------------------------
/test/cases/new_array.js:
--------------------------------------------------------------------------------
1 | var a = new Array();
2 | a.push("hi");
3 | a[0]; //: string
4 |
5 | var b = new Array(true, false, true);
6 | b[0]; //: bool
7 |
8 | var c = new Array(1);
9 | c[0]; //: ?
10 |
11 | var d = new Array("one");
12 | d[0]; //: string
13 |
--------------------------------------------------------------------------------
/test/cases/new_to_prototype.js:
--------------------------------------------------------------------------------
1 | function A() {}
2 | A.prototype.prop_A = 1;
3 | function B() {}
4 | B.prototype = new A;
5 | B.prototype.prop_B = 2;
6 | function C() {}
7 | C.prototype = new A;
8 | C.prototype.prop_C = 3;
9 |
10 | (new A).prop_ //+ prop_A
11 | ;
12 | (new B).prop_ //+ prop_A, prop_B
13 | ;
14 | (new C).prop_ //+ prop_A, prop_C
15 |
--------------------------------------------------------------------------------
/test/cases/node/binary.node:
--------------------------------------------------------------------------------
1 | exports.binary = 1;
2 |
--------------------------------------------------------------------------------
/test/cases/node/dir/index.js:
--------------------------------------------------------------------------------
1 | exports.foo = "hey";
2 | exports.rel = require("./lib/relative");
3 |
--------------------------------------------------------------------------------
/test/cases/node/dir/lib/other.js:
--------------------------------------------------------------------------------
1 | exports.xyz = "foo";
2 |
--------------------------------------------------------------------------------
/test/cases/node/dir/lib/relative.js:
--------------------------------------------------------------------------------
1 | exports.abc = 1;
2 | exports.def = require("./other.js");
3 |
--------------------------------------------------------------------------------
/test/cases/node/exportfunc.js:
--------------------------------------------------------------------------------
1 | var f = module.exports = function(a, b) {
2 | return a + b;
3 | };
4 |
5 | f(1, 2);
6 |
--------------------------------------------------------------------------------
/test/cases/node/localfile.js:
--------------------------------------------------------------------------------
1 | exports.hello = function() { return 10; };
2 |
--------------------------------------------------------------------------------
/test/cases/node/main.js:
--------------------------------------------------------------------------------
1 | // plugin=node
2 |
3 | var fs = require("fs"), crypto = require("crypto"), tls = require("tls"), util = require("util");
4 |
5 | util.error; //: fn(msg: string, ...string: string)
6 | util.inspect; //: fn(object: ?, options: {colors: bool, customInspect: bool, depth: number, maxArrayLength: number, showHidden: bool, showProxy: bool, ...}) -> string
7 |
8 | fs.createReadStream; //: fn(path: string|Buffer, options?: ?) -> fs.ReadStream
9 |
10 | fs.stat("foobar", function(err, stats) {
11 | err; //: Error
12 | stats.isFile(); //: bool
13 | });
14 |
15 | var module = {};
16 |
17 | crypto.getCiphers()[3]; //: string
18 | crypto.createHash("sha1").digest().readUInt16BE(0); //: number
19 |
20 | tls.createServer({}, function(stream) {
21 | // Has event emitter props
22 | stream.once; //: fn(event: string, listener: fn())
23 | // Writable stream props
24 | stream.write; //: fn(chunk: Buffer, encoding?: string, callback?: fn()) -> bool
25 | // Readable stream
26 | stream.read; //: fn(size?: number) -> Buffer
27 | // ClearTextStream
28 | stream.authorized; //: bool
29 | });
30 |
31 | require("timers").setInterval; //: fn(callback: fn(), delay: number, args?: ?) -> timers.Timer
32 | setInterval; //: fn(callback: fn(), delay: number, args?: ?) -> timers.Timer
33 | setTimeout(function(){}, 10).ref; //: fn() -> timers.Timer
34 |
35 |
36 | require("module");
37 |
38 | // don't attempt to handle .node binary modules
39 | require("./binary.node").binary; //: ?
40 |
41 | var mymod = require("mymod");
42 |
43 | require("_stream_readable");
44 |
45 | mymod.foo; //: number
46 | mymod.bar; //: string
47 |
48 | require("./localfile").hello; //: fn() -> number
49 |
50 | require("./foo/../exportfunc.js"); //: fn(a: number, b: number) -> number
51 |
52 | require("./dir"); //:: {foo: string, rel: {abc: number, def: {xyz: string}}}
53 |
54 | var mod1 = require("mod1");
55 | var mod2 = require("mod1/mainfile.js");
56 | mod1.mainExport.x; //: number
57 | mod2.mainExport.x; //: number
58 | mod1.fromSubdep; //: fn()
59 |
60 | require("mod1/secondfile").secondExport.u; //: number
61 | require("mod1/dir1").foo.a; //: number
62 |
63 | require("mod1/reassign_exports").funcPropExport; //loc: 2, 15
64 |
65 | require("mod1/reassign_exports_to_required"); //:: {A: number}
66 |
67 | // inference should continue even if a module is not found
68 | require("mod_not_found"); //: ?
69 |
70 | var doc = require("mod1/doc");
71 | doc.f1; //doc: doc for f1
72 | doc.f2; //doc: doc for f2
73 |
74 | module.exports. //+
75 |
76 | // completion on known require module
77 | require('f' //+ 'fs'
78 | // completion on custom require module
79 | require("my" //+ "mymod"
80 |
81 | // go to definition for modulest
82 | require('./localfile'//loc: 1, 0, localfile.js
83 |
84 | require("./dir/" //+ "./dir/index", "./dir/lib"
85 | require("mod1/d" //+ "mod1/dir1", "mod1/doc"
86 |
87 | require("" //+ "fs", "path", "mod1", ...
88 |
--------------------------------------------------------------------------------
/test/cases/node_exports.js:
--------------------------------------------------------------------------------
1 | // plugin=node
2 |
3 | exports.a = 10;
4 |
5 | exports.b = function() {};
6 |
7 | //exports: {a: number, b: fn()}
8 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/a.js:
--------------------------------------------------------------------------------
1 | exports.A = 1;
2 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/dir1/index.js:
--------------------------------------------------------------------------------
1 | exports.foo = {a: 10};
2 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/doc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // doc for f1
3 | f1: function() { return 7; }
4 | };
5 |
6 | // doc for f2
7 | module.exports.f2 = function() { return 7; };
8 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/mainfile.js:
--------------------------------------------------------------------------------
1 | exports.mainExport = {x: 10, y: 20};
2 |
3 | exports.fromSubdep = require("subdep1").subdepFunc;
4 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/node_modules/subdep1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "subdep1",
3 | "version": "0.0.1",
4 | "main": "subdep1"
5 | }
6 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/node_modules/subdep1/subdep1.js:
--------------------------------------------------------------------------------
1 | exports.subdepFunc = function(){};
2 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "mainfile.js",
3 | "dependencies": {
4 | "subdep1": "0.0.1"
5 | },
6 | "bundledDependencies": ["subdep1"]
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/reassign_exports.js:
--------------------------------------------------------------------------------
1 | module.exports = function() {};
2 | module.exports.funcPropExport = 7;
3 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/reassign_exports_to_required.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./a');
2 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mod1/secondfile.js:
--------------------------------------------------------------------------------
1 | exports.secondExport = {u: 10, v: 20};
2 |
--------------------------------------------------------------------------------
/test/cases/node_modules/mymod.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "mymod",
3 | "exports": {
4 | "foo": "number",
5 | "bar": "string"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/cases/node_origin_paths.js:
--------------------------------------------------------------------------------
1 | // plugin=node
2 |
3 | require('./node/localfile').hello; //origin: node/localfile.js
4 |
--------------------------------------------------------------------------------
/test/cases/object-string-prop.js:
--------------------------------------------------------------------------------
1 |
2 | var obj = {
3 | Test: "Hello"
4 | };
5 |
6 | obj = {
7 | "T //+ Test
8 | };
--------------------------------------------------------------------------------
/test/cases/object_create.js:
--------------------------------------------------------------------------------
1 | var base = {foo: 10, bar: 20};
2 | var gen1 = Object.create(base);
3 | var gen2 = Object.create(gen1);
4 |
5 | base.baz = 30;
6 | gen1.quux = 50;
7 | gen2.kaka = 10;
8 |
9 | gen1.foo; //: number
10 |
11 | gen2.foo; //: number
12 |
13 | gen1.baz; //: number
14 |
15 | gen2.baz; //: number
16 |
17 | gen1.quux; //: number
18 |
19 | gen2.quux; //: number
20 |
21 | gen1.kaka; //: ?
22 |
23 | var extend = Object.create(base, {prop1: {value: "hi"}, prop2: {}});
24 |
25 | extend.prop1; //: string
26 |
27 | extend.bar; //: number
28 |
29 | var empty = Object.create(null);
30 | empty.prop1 = "hi";
31 |
32 | empty.hasOwnProperty; //: ?
33 | empty.prop1; //: string
34 |
35 | function create() {
36 | // Implementation
37 | }
38 |
39 | module.exports = {
40 | create //loc: 35,9
41 | };
42 |
43 | module.exports = {
44 | create: create //loc: 35,9
45 | };
--------------------------------------------------------------------------------
/test/cases/objectlit.js:
--------------------------------------------------------------------------------
1 | var bar
2 |
3 | var foo = {
4 | [bar = 100]: 44,
5 | __proto__: baz,
6 | a: true,
7 | method() { return "ok" }
8 | }
9 |
10 | var baz = {
11 | __proto__: null,
12 | b: "hi"
13 | }
14 |
15 | foo.a //: bool
16 | foo.method() //: string
17 | foo.b //: string
18 | foo.toString //: ?
19 |
--------------------------------------------------------------------------------
/test/cases/objnames.js:
--------------------------------------------------------------------------------
1 | function Ctor1() { this.x = 10; }
2 | Ctor1.prototype = {a: 1};
3 |
4 | function Ctor2() {}
5 |
6 | var singleton = {a: 10, b: 20}; //: singleton
7 |
8 | new Ctor1(); //: Ctor1
9 | new Ctor2(); //: Ctor2
10 |
--------------------------------------------------------------------------------
/test/cases/or_empty_array.js:
--------------------------------------------------------------------------------
1 | var x = "foo".match(/o/) || []
2 |
3 | x //: [string]
4 |
--------------------------------------------------------------------------------
/test/cases/order_of_definition.js:
--------------------------------------------------------------------------------
1 | foo.bar.baz.bug({
2 | prop: function() {
3 | this.a; //: bool
4 | }
5 | });
6 |
7 | var foo = {};
8 |
9 | var baz = {bug: function(o) {
10 | function x() { this.a = true; }
11 | x.prototype = o;
12 | return new x;
13 | }};
14 |
15 | foo.bar = {baz: baz};
16 |
--------------------------------------------------------------------------------
/test/cases/phantom_object.js:
--------------------------------------------------------------------------------
1 | var mod = window.mymodule
2 |
3 | mod.func = function() { return 10 }
4 |
5 | mod.func //: fn() -> number
6 |
7 | var otherMod = window.yourmodule.theirmodule
8 |
9 | otherMod.c = 10
10 |
11 | otherMod.c //: number
12 |
--------------------------------------------------------------------------------
/test/cases/plus.js:
--------------------------------------------------------------------------------
1 | var x = 10;
2 | var y = "foo";
3 |
4 | x + 20; //: number
5 | x + y; //: string
6 | "foo" + y; //: string
7 | "foo" + x; //: string
8 |
--------------------------------------------------------------------------------
/test/cases/promise.js:
--------------------------------------------------------------------------------
1 | var p = new Promise(function(accept, reject) {
2 | reject; //: fn(reason: ?)
3 | accept({x: 20});
4 | });
5 |
6 | p.; //+ then, catch, finally
7 |
8 | p.then(function(value) {
9 | value; //:: {x: number}
10 | }).then(function(value) {
11 | value; //:: {x: number}
12 | });
13 |
14 | var p2 = new Promise(function(acc) { acc("hi"); });
15 |
16 | Promise.all([p2]).then(function(value) {
17 | value; //: [string]
18 | return Promise.resolve(33);
19 | }).then(function(value) {
20 | value; //: number
21 | });
22 |
23 | var p3 = Promise.resolve(10);
24 |
25 | p3.then(function(value) {
26 | value; //: number
27 | return true;
28 | }).then(function(value) {
29 | value; //: bool
30 | });
31 |
32 | var p4 = Promise.resolve(Promise.resolve(10));
33 | p4.then(function(value) {
34 | value; //: number
35 | });
36 |
37 | var arg5 = 1 < 2 ? Promise.resolve(10) : 20;
38 | var p5 = Promise.resolve(arg5);
39 | p5.then(function(value) {
40 | value; //: number
41 | });
42 |
43 | var p6 = Promise.resolve('t').then(function() {
44 | return 1 < 2 ? Promise.resolve(10) : 20;
45 | }).then(function(value) {
46 | value; //: number
47 | });
48 |
49 | var p7 = Promise.resolve().then(function() {
50 | return 20;
51 | }).then(function(value) {
52 | value; //: number
53 | });
54 |
55 | var p8 = Promise.resolve();
56 | p8 //: Promise
57 |
58 | function myResolve1(arg) {
59 | return Promise.resolve(arg);
60 | }
61 |
62 | myResolve1('s') //:: {:t: string}
63 |
64 | function myResolve2(arg) {
65 | return Promise.resolve(arg);
66 | }
67 |
68 | myResolve2('s') //:: {:t: string|number}
69 | myResolve2(4) //:: {:t: string|number}
70 |
71 | myResolve2('s').then(function(value) {
72 | value; //: string|number
73 | })
74 |
75 | function myResolve3(arg7) {
76 | return Promise.resolve(arg7);
77 | }
78 |
79 | myResolve3(Promise.resolve(4)).then(function(value) {
80 | value; //: number
81 | });
82 |
83 | myResolve3(Promise.resolve(4)) //:: {:t: number}
84 |
85 | myResolve3(4).then(function(value) {
86 | value; //: number
87 | });
88 |
--------------------------------------------------------------------------------
/test/cases/proto.js:
--------------------------------------------------------------------------------
1 | function Foo(x) {
2 | this.x = x;
3 | this.y = [1];
4 | }
5 | Foo; //: fn(x: bool)
6 |
7 | Foo.prototype = {
8 | makeString: function() { return "hi"; },
9 | bar: 13
10 | };
11 |
12 | var z = new Foo(true); //:: {x: bool, y: [number]}
13 |
14 | z.toString; //: fn() -> string
15 |
16 | z.bar; //: number
17 |
--------------------------------------------------------------------------------
/test/cases/protoname.js:
--------------------------------------------------------------------------------
1 | function Base() {}
2 | Base.prototype = {};
3 |
4 | Base.prototype; //: Base.prototype
5 | new Base; //: Base
6 |
7 | function Sub1() {}
8 | Sub1.prototype = new Base();
9 | new Sub1(); //: Sub1
10 |
11 | function Sub2() {}
12 | Sub2.prototype = Object.create(Base.prototype);
13 | new Sub2(); //: Sub2
14 |
15 | function Base2() {}
16 |
17 | function Sub3() {}
18 | Sub3.prototype = new Base2();
19 |
20 | new Sub3(); //: Sub3
21 |
--------------------------------------------------------------------------------
/test/cases/replace_bogus_prop.js:
--------------------------------------------------------------------------------
1 | var x = new Type();
2 |
3 | x.foo; //: string
4 |
5 | function Type() {}
6 | Type.prototype.foo = "hi";
7 |
--------------------------------------------------------------------------------
/test/cases/requirejs/bar.js:
--------------------------------------------------------------------------------
1 | define(["baz"], function(baz) {
2 | return {aNumber: 10, baz: baz};
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/baz.js:
--------------------------------------------------------------------------------
1 | define("foo", function(foo) {
2 | return {bazProp: new Date, bazFooProp: foo.aString};
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/foo.js:
--------------------------------------------------------------------------------
1 | define({aString: "hello"});
2 |
--------------------------------------------------------------------------------
/test/cases/requirejs/func.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports, module){
2 | function aFunction() { return false; }
3 | return aFunction;
4 | });
5 |
--------------------------------------------------------------------------------
/test/cases/requirejs/main.js:
--------------------------------------------------------------------------------
1 | // environment=browser
2 | // environment=jquery
3 | // plugin=requirejs {"override": {"jquery": "=$"}}
4 |
5 | requirejs(["foo", "bar!abc", "useexports", "simplifiedcommon", "subdir/zap", "module_exports"],
6 | function(foo, bar, useexports, simplified, zap, module_exports) {
7 | foo.aString; //: string
8 | bar.aNumber; //: number
9 | bar.baz.bazProp; //: Date
10 | bar.baz.bazFooProp; //: string
11 | useexports.hello; //: bool
12 | simplified.hello; //: string
13 | simplified.func; //: fn() -> bool
14 | zap; //: string
15 | module_exports; //:: {one: number, two: number}
16 |
17 | foo; //origin: foo.js
18 | bar; //origin: bar.js
19 | bar.baz; //origin: baz.js
20 | });
21 |
22 | requirejs(["jquery"], function($) {
23 | $.fx.off; //: bool
24 | });
25 |
26 | requirejs(["require"], function(require) {
27 | require("jquery").fx.off; //: bool
28 | require("requireme").someprop; //: string
29 | });
30 |
31 | requirejs(["named"], function(named) {
32 | named.foo; //:: {a: number}
33 | });
34 |
35 | requirejs.config({
36 | p //+ packages, paths, ...
37 | });
38 |
39 | requirejs.config({
40 | //+ baseUrl, config, context, map, nodeIdCompat, packages, paths, shim, ...
41 | });
42 |
43 | requirejs.config({
44 | baseUrl: '',
45 | //+ config, context, map, nodeIdCompat, packages, paths, shim, ...
46 | });
47 |
48 | var c1 = {
49 | pa //?+ packages, paths, ...
50 | }
51 | requirejs.config(c1);
52 |
53 | var c2 = {
54 | //?+ baseUrl, config, context, map, nodeIdCompat, packages, paths, shim, ...
55 | }
56 | requirejs.config(c2);
57 |
58 | var c3 = {
59 | baseUrl: '',
60 | //?+ config, context, map, nodeIdCompat, packages, paths, shim, ...
61 | }
62 | requirejs.config(c3);
63 |
--------------------------------------------------------------------------------
/test/cases/requirejs/module_exports.js:
--------------------------------------------------------------------------------
1 | define(["module"], function(module) {
2 | module.exports = {one: 1, two: 2};
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/named.js:
--------------------------------------------------------------------------------
1 | define("myname", ["exports"], function(exports) {
2 | exports.foo = {a: 10};
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/requireme.js:
--------------------------------------------------------------------------------
1 | define(["exports"], function(exports) {
2 | exports.someprop = "a string";
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/simplifiedcommon.js:
--------------------------------------------------------------------------------
1 | define(function(require, exports) {
2 | exports.hello = require("foo").aString;
3 | exports.func = require("func");
4 | });
5 |
--------------------------------------------------------------------------------
/test/cases/requirejs/subdir/zap.js:
--------------------------------------------------------------------------------
1 | define(["../foo"], function(foo) {
2 | return foo.aString;
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs/useexports.js:
--------------------------------------------------------------------------------
1 | define(["exports"], function(exports) {
2 | exports.hello = true;
3 | });
4 |
--------------------------------------------------------------------------------
/test/cases/requirejs_config/main.js:
--------------------------------------------------------------------------------
1 | // plugin=requirejs
2 |
3 | requirejs.config({
4 | paths: {
5 | fooAlias: "../requirejs/foo"
6 | }
7 | });
8 |
9 | require(["fooAlias"], function(foo) {
10 | foo.aString; //: string
11 | });
12 |
--------------------------------------------------------------------------------
/test/cases/set.js:
--------------------------------------------------------------------------------
1 | let set = new Set
2 |
3 | set.add(true)
4 | set.size //: number
5 | set.has(true) //: bool
6 |
7 | for (var elt of set.values())
8 | elt //: bool
9 |
10 | set.forEach(function(val) {
11 | val //: bool
12 | })
13 |
--------------------------------------------------------------------------------
/test/cases/simple.js:
--------------------------------------------------------------------------------
1 | var foo = (function() {
2 | return 42;
3 | })();
4 | foo; //: number
5 |
6 | var x = {};
7 |
8 | function init(v) {
9 | v.foo = 10;
10 | v.bar = 1 + 1;
11 | }
12 | init; //:: fn(v: {bar: number, foo: number})
13 |
14 | init(x);
15 | x; //:: {bar: number, foo: number}
16 |
--------------------------------------------------------------------------------
/test/cases/simple_generic.js:
--------------------------------------------------------------------------------
1 | function last(arr) { return arr[arr.length - 1]; }
2 |
3 | last([1, 2, 3]); //: number
4 | last(["a", "b", "c"]); //: string
5 |
6 | function map(arr, f) {
7 | var res = [];
8 | for (var i = 0; i < arr.length; ++i) res.push(f(arr[i]));
9 | return res;
10 | }
11 |
12 | map([1, 2, 3], function() { return "X"; }); //: [string]
13 | map([1, 2, 3], function() { return true; }); //: [bool]
14 |
--------------------------------------------------------------------------------
/test/cases/span_from_def.js:
--------------------------------------------------------------------------------
1 | // environment=span
2 |
3 | iHaveASpan; //loc: 4, 2
4 |
--------------------------------------------------------------------------------
/test/cases/super.js:
--------------------------------------------------------------------------------
1 | class Point3 extends Point2 {
2 | constructor(x, y, z) { super(x, y); this.z = z }
3 | foobar() { return this.x }
4 | callSuper() { return super.hello() }
5 | }
6 |
7 | class Point2 {
8 | constructor(x, y) { this.x = x; this.y = y }
9 | hello() { return "hello" }
10 | }
11 |
12 | var p = new Point3(1, 2, 3)
13 | p.x //: number
14 | p.hello() //: string
15 | p.callSuper() //: string
16 | p.foobar() //: number
17 |
18 | var pro = {x: 10}
19 |
20 | var obj = {
21 | __proto__: pro,
22 | x: "string",
23 | getSuperX() { return super.x }
24 | }
25 |
26 | obj.x //: string
27 | obj.getSuperX() //: number
28 |
--------------------------------------------------------------------------------
/test/cases/symbol.js:
--------------------------------------------------------------------------------
1 | var mySym = Symbol("my sym")
2 |
3 | var obj = {
4 | [mySym]: 22
5 | }
6 | obj[mySym] //: number
7 |
8 | obj[Symbol.iterator] = "hello"
9 | obj[Symbol.iterator] //: string
10 |
--------------------------------------------------------------------------------
/test/cases/template.js:
--------------------------------------------------------------------------------
1 | `foo` //: string
2 | var x
3 | `foo${x = 10}bar` //: string
4 | x //: number
5 |
6 | function build(strs, a, b) {
7 | strs //: [string]
8 | a //: number
9 | b //: string
10 | return true
11 | }
12 |
13 | build`foo${10}bar${'hi'}` //: bool
14 |
--------------------------------------------------------------------------------
/test/cases/underscore.js:
--------------------------------------------------------------------------------
1 | // environment=underscore
2 |
3 | var cloneObjOrig = {a: 1}, cloneObjCopy = _.clone(cloneObjOrig);
4 | cloneObjOrig.a; //: number
5 | cloneObjCopy.a; //: number
6 |
7 | var extendObj = {a: 1, b: true};
8 | _.extend(extendObj, {c: ''}, {d: 2});
9 | extendObj; //:: {a: number, b: bool, c: string, d: number}
10 |
11 | var defaulted = {x: 10};
12 | _.defaults(defaulted, {y: ""});
13 | defaulted.x; //: number
14 | defaulted.y; //: string
15 |
16 | _.has({}, "foo"); //: bool
17 | _.isNaN(NaN); //: bool
18 |
19 | var tapped;
20 | _.tap(11, function(a) { tapped = a; });
21 | tapped; //: number
22 |
23 | _.reduce(["foo", "bar"], function(sum, s) { return sum + s.length; }, 0); //: number
24 | _.map([1, 2, 3], toString); //: [string]
25 | _.each([true, false], function(val, i) {
26 | val; //: bool
27 | i; //: number
28 | this.aa; //: number
29 | }, {aa: 4});
30 |
--------------------------------------------------------------------------------
/test/cases/webpack/component/foo.js:
--------------------------------------------------------------------------------
1 | module.exports = {index: true}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/main.js:
--------------------------------------------------------------------------------
1 | // plugin=webpack {"configPath": "./webpack.config.js"}
2 |
3 | require("foo") //:: {browser: bool}
4 |
5 | require("foo/index") //:: {index: bool}
6 |
7 | require("./component/foo") //:: {index: bool}
8 |
9 | require("component/foo") //:: {index: bool}
10 |
11 | require("xyz") //:: {index: bool}
12 |
13 | require("esnext") //:: {default: {index: bool}}
14 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/esnext/index.js:
--------------------------------------------------------------------------------
1 | export default {index: true}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/esnext/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "jsnext:main": "index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/foo/browser.js:
--------------------------------------------------------------------------------
1 | module.exports = {browser: true}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/foo/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {index: true}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/foo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "browser": "browser.js"
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/modu/index.js:
--------------------------------------------------------------------------------
1 | module.exports = { index: true}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/modu/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/xyz/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {index: false}
2 |
--------------------------------------------------------------------------------
/test/cases/webpack/node_modules/xyz/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js"
3 | }
4 |
--------------------------------------------------------------------------------
/test/cases/webpack/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path')
2 |
3 | module.exports = {
4 | resolve: {
5 | packageMains: ['jsnext:main', 'browser', 'browserify', 'main'],
6 | root: __dirname,
7 | alias: {
8 | xyz: "modu"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/condense.js:
--------------------------------------------------------------------------------
1 | var util = require("./util");
2 | var tern = require("../lib/tern"), condense = require("../lib/condense");
3 | var fs = require("fs"), path = require("path");
4 | require("../plugin/angular");
5 | require("../plugin/node");
6 |
7 | var condenseDir = "test/condense";
8 | function jsonFile(name) { return util.resolve(condenseDir + "/" + name.replace(/\.js$/, ".json")); }
9 |
10 | function runTest(options) {
11 | var server = new tern.Server({
12 | defs: [util.ecmascript, util.browser],
13 | plugins: options.plugins,
14 | projectDir: util.resolve(condenseDir),
15 | getFile: function(name) {
16 | return fs.readFileSync(path.resolve(condenseDir, name), "utf8");
17 | }
18 | });
19 | options.load.forEach(function(file) {
20 | server.addFile(file);
21 | });
22 | server.flush(function() {
23 | var origins = options.include || options.load;
24 | var condensed = condense.condense(origins, null, {sortOutput: true});
25 | var out = JSON.stringify(condensed, null, 2);
26 | var expect = fs.readFileSync(jsonFile(origins[0]), "utf8").trim();
27 | if (out != expect)
28 | return util.failure("condense/" + origins[0] + ": Mismatch in condense output. Got " +
29 | out + "\nExpected " + expect);
30 |
31 | // Test loading the condensed defs.
32 | var server2 = new tern.Server({
33 | defs: [util.ecmascript, util.browser, condensed],
34 | plugins: options.plugins
35 | });
36 | server2.flush(function() {
37 | var condensed = condense.condense(origins, null, {sortOutput: true});
38 | var out = JSON.stringify(condensed, null, 2);
39 | if (out != expect)
40 | util.failure("condense/" + origins[0] + ": Mismatch in condense output after loading defs. Got " +
41 | out + "\nExpected " + expect);
42 | });
43 | });
44 | }
45 |
46 | exports.runTests = function(filter) {
47 | function jsFile(f) {
48 | return f + ".js";
49 | }
50 | function test(options) {
51 | if (typeof options == "string") options = {load: [options]};
52 | options.load = options.load.map(jsFile);
53 | if (options.include) options.include = options.include.map(jsFile);
54 | if (filter && options.load[0].indexOf(filter) == -1) return;
55 | util.addTest();
56 | util.addFile();
57 | runTest(options);
58 | }
59 |
60 | test("basic");
61 | test("fn");
62 | test("add_to_old");
63 | test({load: ["ignore_newer", "extend_foo"],
64 | include: ["ignore_newer"]});
65 | test("ref_to_old");
66 | test("ref_in_type");
67 | test("double_ref");
68 | test("proto");
69 | test("generic");
70 | test("array");
71 | test("function_prop");
72 | test("uniontype");
73 |
74 | test({load: ["node_simple"], plugins: {node: true}});
75 | test({load: ["node_require_private"], plugins: {node: true}});
76 | test({load: ["node_fn_export"], plugins: {node: true}});
77 | test({load: ["node_other_module_type_ref"], include: ["node_other_module_type_ref", "node_export_function_a"], plugins: {node: true}});
78 |
79 | test({load: ["angular_simple"], plugins: {angular: true}});
80 |
81 | test({load: ["requirejs_const"], plugins: {requirejs: true}});
82 | test({load: ["requirejs_primitive"], plugins: {requirejs: true}});
83 | test({load: ["requirejs_setup"], plugins: {requirejs: true}});
84 | test({load: ["requirejs_empty_deps"], plugins: {requirejs: true}});
85 | // TODO(sqs): if load order is reversed, then
86 | // !define.!requirejs.requirejs_dep.a duplicates the definition instead of
87 | // referring to !requirejs.requirejs_const.
88 | test({load: ["requirejs_const", "requirejs_dep"], include: ["requirejs_dep", "requirejs_const"], plugins: {requirejs: true}});
89 |
90 | test("recursive");
91 | };
92 |
--------------------------------------------------------------------------------
/test/condense/add_to_old.js:
--------------------------------------------------------------------------------
1 | function Thing() {}
2 |
3 | Element.prototype.foo = new Thing;
4 |
--------------------------------------------------------------------------------
/test/condense/add_to_old.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "add_to_old.js",
3 | "Element": {
4 | "prototype": {
5 | "foo": {
6 | "!span": "39[2:18]-42[2:21]",
7 | "!type": "+Thing"
8 | }
9 | }
10 | },
11 | "Thing": {
12 | "!span": "9[0:9]-14[0:14]",
13 | "!type": "fn()"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/test/condense/angular_simple.js:
--------------------------------------------------------------------------------
1 | angular.module("foo", []).value("fooVal", {info: "info"}});
2 |
3 | angular.module("test", ["foo"])
4 | // Doc for testVal
5 | .factory("testVal", function() {
6 | return "hi";
7 | });
8 |
--------------------------------------------------------------------------------
/test/condense/angular_simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!ng": {
4 | "foo": {
5 | "!data": {
6 | "includes": []
7 | },
8 | "!proto": "angular.Module.prototype",
9 | "_inject_fooVal": {
10 | "!span": "32[0:32]-40[0:40]",
11 | "info": {
12 | "!span": "43[0:43]-47[0:47]",
13 | "!type": "string"
14 | }
15 | }
16 | },
17 | "test": {
18 | "!data": {
19 | "includes": [
20 | "foo"
21 | ]
22 | },
23 | "!proto": "angular.Module.prototype",
24 | "_inject_testVal": {
25 | "!doc": "Doc for testVal",
26 | "!span": "121[4:9]-130[4:18]",
27 | "!type": "string"
28 | }
29 | }
30 | }
31 | },
32 | "!name": "angular_simple.js"
33 | }
34 |
--------------------------------------------------------------------------------
/test/condense/array.js:
--------------------------------------------------------------------------------
1 | var x = [{a: 10, b: true}];
2 |
--------------------------------------------------------------------------------
/test/condense/array.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "x.": {
4 | "!span": "9[0:9]-25[0:25]",
5 | "a": {
6 | "!span": "10[0:10]-11[0:11]",
7 | "!type": "number"
8 | },
9 | "b": {
10 | "!span": "17[0:17]-18[0:18]",
11 | "!type": "bool"
12 | }
13 | }
14 | },
15 | "!name": "array.js",
16 | "x": {
17 | "!span": "4[0:4]-5[0:5]",
18 | "!type": "[x.]"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/test/condense/basic.js:
--------------------------------------------------------------------------------
1 | var x = 10;
2 | var y = {
3 | foo: 20,
4 | bar: "hi";
5 | };
6 |
--------------------------------------------------------------------------------
/test/condense/basic.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "basic.js",
3 | "x": {
4 | "!span": "4[0:4]-5[0:5]",
5 | "!type": "number"
6 | },
7 | "y": {
8 | "!span": "16[1:4]-17[1:5]",
9 | "bar": {
10 | "!span": "35[3:2]-38[3:5]",
11 | "!type": "string"
12 | },
13 | "foo": {
14 | "!span": "24[2:2]-27[2:5]",
15 | "!type": "number"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/test/condense/double_ref.js:
--------------------------------------------------------------------------------
1 | var a = {an: "object"};
2 | var b = a;
3 |
--------------------------------------------------------------------------------
/test/condense/double_ref.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "double_ref.js",
3 | "a": {
4 | "!span": "4[0:4]-5[0:5]",
5 | "an": {
6 | "!span": "9[0:9]-11[0:11]",
7 | "!type": "string"
8 | }
9 | },
10 | "b": "a"
11 | }
12 |
--------------------------------------------------------------------------------
/test/condense/extend_foo.js:
--------------------------------------------------------------------------------
1 | foo.z = {something: "else"};
2 |
--------------------------------------------------------------------------------
/test/condense/fn.js:
--------------------------------------------------------------------------------
1 | function a(){}
2 | var b = a;
3 |
--------------------------------------------------------------------------------
/test/condense/fn.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "fn.js",
3 | "a": {
4 | "!span": "9[0:9]-10[0:10]",
5 | "!type": "fn()"
6 | },
7 | "b": "a"
8 | }
9 |
--------------------------------------------------------------------------------
/test/condense/function_prop.js:
--------------------------------------------------------------------------------
1 | foo = function() {};
2 | foo.s = '';
3 |
--------------------------------------------------------------------------------
/test/condense/function_prop.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "function_prop.js",
3 | "foo": {
4 | "!span": "0[0:0]-3[0:3]",
5 | "!type": "fn()",
6 | "s": {
7 | "!span": "25[1:4]-26[1:5]",
8 | "!type": "string"
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/condense/generic.js:
--------------------------------------------------------------------------------
1 | function x(y) { return y.bar; }
2 |
--------------------------------------------------------------------------------
/test/condense/generic.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "generic.js",
3 | "x": {
4 | "!span": "9[0:9]-10[0:10]",
5 | "!type": "fn(y: ?) -> !0.bar"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/condense/ignore_newer.js:
--------------------------------------------------------------------------------
1 | var foo = {
2 | x: 10,
3 | y: 20
4 | };
5 |
--------------------------------------------------------------------------------
/test/condense/ignore_newer.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "ignore_newer.js",
3 | "foo": {
4 | "!span": "4[0:4]-7[0:7]",
5 | "x": {
6 | "!span": "14[1:2]-15[1:3]",
7 | "!type": "number"
8 | },
9 | "y": {
10 | "!span": "23[2:2]-24[2:3]",
11 | "!type": "number"
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/condense/node_export_function_a.js:
--------------------------------------------------------------------------------
1 | exports.a = function(){};
2 |
--------------------------------------------------------------------------------
/test/condense/node_fn_export.js:
--------------------------------------------------------------------------------
1 | module.exports = function(a) { return a; };
2 |
--------------------------------------------------------------------------------
/test/condense/node_fn_export.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!modules": {
4 | "node_fn_export`js": {
5 | "!span": "17[0:17]-42[0:42]",
6 | "!type": "fn(a: ?) -> !0"
7 | }
8 | }
9 | },
10 | "!name": "node_fn_export.js"
11 | }
12 |
--------------------------------------------------------------------------------
/test/condense/node_other_module_type_ref.js:
--------------------------------------------------------------------------------
1 | exports.b = require('./node_export_function_a').a;
2 |
--------------------------------------------------------------------------------
/test/condense/node_other_module_type_ref.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!modules": {
4 | "node_export_function_a`js": {
5 | "!span": "0[0:0]-26[1:0]",
6 | "a": {
7 | "!span": "8[0:8]-9[0:9]",
8 | "!type": "fn()"
9 | }
10 | },
11 | "node_other_module_type_ref`js": {
12 | "!span": "0[0:0]-51[1:0]",
13 | "b": "!modules.node_export_function_a`js.a"
14 | }
15 | }
16 | },
17 | "!name": "node_other_module_type_ref.js"
18 | }
19 |
--------------------------------------------------------------------------------
/test/condense/node_require_private.js:
--------------------------------------------------------------------------------
1 | // "freelist" could be any other undocumented node.js API module that isn't
2 | // included in the tern node plugin definitions.
3 | require('freelist');
4 |
--------------------------------------------------------------------------------
/test/condense/node_require_private.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "node_require_private.js"
3 | }
4 |
--------------------------------------------------------------------------------
/test/condense/node_simple.js:
--------------------------------------------------------------------------------
1 | exports.a = 10;
2 | exports.b = function() { return exports.a; };
3 |
--------------------------------------------------------------------------------
/test/condense/node_simple.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!modules": {
4 | "node_simple`js": {
5 | "!span": "0[0:0]-62[2:0]",
6 | "a": {
7 | "!span": "8[0:8]-9[0:9]",
8 | "!type": "number"
9 | },
10 | "b": {
11 | "!span": "24[1:8]-25[1:9]",
12 | "!type": "fn() -> number"
13 | }
14 | }
15 | }
16 | },
17 | "!name": "node_simple.js"
18 | }
19 |
--------------------------------------------------------------------------------
/test/condense/proto.js:
--------------------------------------------------------------------------------
1 | var x = {my: "object"};
2 | var y = Object.create(x);
3 | y.bar = "extended";
4 |
--------------------------------------------------------------------------------
/test/condense/proto.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "proto.js",
3 | "x": {
4 | "!span": "4[0:4]-5[0:5]",
5 | "my": {
6 | "!span": "9[0:9]-11[0:11]",
7 | "!type": "string"
8 | }
9 | },
10 | "y": {
11 | "!proto": "x",
12 | "!span": "28[1:4]-29[1:5]",
13 | "bar": {
14 | "!span": "52[2:2]-55[2:5]",
15 | "!type": "string"
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/test/condense/recursive.js:
--------------------------------------------------------------------------------
1 | var b = {};
2 | b[3] = [b[3]];
3 |
--------------------------------------------------------------------------------
/test/condense/recursive.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "recursive.js",
3 | "b": {
4 | "!span": "4[0:4]-5[0:5]",
5 | "": {
6 | "!span": "14[1:2]-15[1:3]",
7 | "!type": "[b.]"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/test/condense/ref_in_type.js:
--------------------------------------------------------------------------------
1 | function out(a) { return a.bar + 10; }
2 |
3 | (function() {
4 | function Foo() { this.bar = 10; }
5 | out(new Foo);
6 | })();
7 |
--------------------------------------------------------------------------------
/test/condense/ref_in_type.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "out.!0": {
4 | "bar": {
5 | "!span": "78[3:24]-81[3:27]",
6 | "!type": "number"
7 | }
8 | }
9 | },
10 | "!name": "ref_in_type.js",
11 | "out": {
12 | "!span": "9[0:9]-12[0:12]",
13 | "!type": "fn(a: out.!0) -> number"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/test/condense/ref_to_old.js:
--------------------------------------------------------------------------------
1 | var myElement = new Date();
2 |
--------------------------------------------------------------------------------
/test/condense/ref_to_old.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "ref_to_old.js",
3 | "myElement": {
4 | "!span": "4[0:4]-13[0:13]",
5 | "!type": "+Date"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/test/condense/requirejs_const.js:
--------------------------------------------------------------------------------
1 | define({a: "a"});
2 |
--------------------------------------------------------------------------------
/test/condense/requirejs_const.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!requirejs": {
4 | "requirejs_const": {
5 | "!span": "7[0:7]-15[0:15]",
6 | "a": {
7 | "!span": "8[0:8]-9[0:9]",
8 | "!type": "string"
9 | }
10 | }
11 | }
12 | },
13 | "!name": "requirejs_const.js"
14 | }
15 |
--------------------------------------------------------------------------------
/test/condense/requirejs_dep.js:
--------------------------------------------------------------------------------
1 | define(['./requirejs_const'], function(requirejs_const) {
2 | return {a: requirejs_const};
3 | });
4 |
--------------------------------------------------------------------------------
/test/condense/requirejs_dep.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!requirejs": {
4 | "requirejs_const": {
5 | "!span": "7[0:7]-15[0:15]",
6 | "a": {
7 | "!span": "8[0:8]-9[0:9]",
8 | "!type": "string"
9 | }
10 | },
11 | "requirejs_dep": {
12 | "!span": "67[1:9]-87[1:29]",
13 | "a": "!requirejs.requirejs_const"
14 | }
15 | }
16 | },
17 | "!name": "requirejs_dep.js"
18 | }
19 |
--------------------------------------------------------------------------------
/test/condense/requirejs_empty_deps.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | return {c: "c"};
3 | });
4 |
--------------------------------------------------------------------------------
/test/condense/requirejs_empty_deps.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!requirejs": {
4 | "requirejs_empty_deps": {
5 | "!span": "33[1:9]-41[1:17]",
6 | "c": {
7 | "!span": "34[1:10]-35[1:11]",
8 | "!type": "string"
9 | }
10 | }
11 | }
12 | },
13 | "!name": "requirejs_empty_deps.js"
14 | }
15 |
--------------------------------------------------------------------------------
/test/condense/requirejs_primitive.js:
--------------------------------------------------------------------------------
1 | define([], function() {
2 | return 1;
3 | });
4 |
--------------------------------------------------------------------------------
/test/condense/requirejs_primitive.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!requirejs": {
4 | "requirejs_primitive": "number"
5 | }
6 | },
7 | "!name": "requirejs_primitive.js"
8 | }
9 |
--------------------------------------------------------------------------------
/test/condense/requirejs_setup.js:
--------------------------------------------------------------------------------
1 | define(function() {
2 | return {b: "b"};
3 | });
4 |
--------------------------------------------------------------------------------
/test/condense/requirejs_setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "!define": {
3 | "!requirejs": {
4 | "requirejs_setup": {
5 | "!span": "29[1:9]-37[1:17]",
6 | "b": {
7 | "!span": "30[1:10]-31[1:11]",
8 | "!type": "string"
9 | }
10 | }
11 | }
12 | },
13 | "!name": "requirejs_setup.js"
14 | }
15 |
--------------------------------------------------------------------------------
/test/condense/uniontype.js:
--------------------------------------------------------------------------------
1 | function x(a) {}
2 | function y() { if (something) return true; else return 100; }
3 |
4 | x("hi");
5 | x([10]);
6 | y();
7 |
--------------------------------------------------------------------------------
/test/condense/uniontype.json:
--------------------------------------------------------------------------------
1 | {
2 | "!name": "uniontype.js",
3 | "x": {
4 | "!span": "9[0:9]-10[0:10]",
5 | "!type": "fn(a: string|[number])"
6 | },
7 | "y": {
8 | "!span": "26[1:9]-27[1:10]",
9 | "!type": "fn() -> bool|number"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/test/data/large.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs");
2 | var rmrf = require("rimraf");
3 | var yaml = require("js-yaml");
4 | var marked = require("marked");
5 | var Mold = require("mold-template");
6 | var util = require("./util");
7 | CodeMirror = require("codemirror/addon/runmode/runmode.node.js");
8 |
9 | marked.setOptions({highlight: highlightCode, gfm: true});
10 |
11 | function highlightCode(code, lang) {
12 | if (!lang) return code;
13 | if (!CodeMirror.modes.hasOwnProperty(lang)) {
14 | try { require("codemirror/mode/" + lang + "/" + lang); }
15 | catch(e) { console.log(e.toString());CodeMirror.modes[lang] = false; }
16 | }
17 | if (CodeMirror.modes[lang]) {
18 | var html = "";
19 | CodeMirror.runMode(code, lang, function(token, style) {
20 | if (style) html += "" + Mold.escapeHTML(token) + " ";
21 | else html += Mold.escapeHTML(token);
22 | });
23 | return html;
24 | } else return code;
25 | }
26 |
27 | function hasFrontMatter(file) {
28 | var fd = fs.openSync(file, "r");
29 | var b = new Buffer(4);
30 | var ret = fs.readSync(fd, b, 0, 4, 0) == 4 && b.toString() == "---\n";
31 | fs.closeSync(fd);
32 | return ret;
33 | }
34 |
35 | function readFrontMatter(file) {
36 | if (/^---\n/.test(file)) {
37 | var end = file.search(/\n---\n/);
38 | if (end != -1) return {front: yaml.load(file.slice(4, end + 1)) || {}, main: file.slice(end + 5)};
39 | }
40 | return {front: {}, main: file};
41 | }
42 |
43 | function readPosts(config) {
44 | var posts = [];
45 | fs.readdirSync("_posts/").forEach(function(file) {
46 | var d = file.match(/^(\d{4})-(\d\d?)-(\d\d?)-(.+)\.(md|link)$/);
47 | var split = readFrontMatter(fs.readFileSync("_posts/" + file, "utf8"));
48 | var post = split.front;
49 | post.date = new Date(d[1], d[2] - 1, d[3]);
50 | post.name = d[4];
51 | if (!post.tags) post.tags = [];
52 | if (!post.tags.forEach && post.tags.split) post.tags = post.tags.split(/\s+/);
53 | if (d[5] == "md") {
54 | post.content = marked(split.main);
55 | post.url = getURL(config, post);
56 | } else if (d[5] == "link") {
57 | var escd = Mold.escapeHTML(post.url);
58 | post.content = " Read this post at " + escd + " .
";
59 | post.isLink = true;
60 | }
61 | posts.push(post);
62 | });
63 | posts.sort(function(a, b){return b.date - a.date;});
64 | return posts;
65 | }
66 |
67 | function gatherTags(posts) {
68 | var tags = {};
69 | posts.forEach(function(post) {
70 | if (post.tags) post.tags.forEach(function(tag) {
71 | (tags.hasOwnProperty(tag) ? tags[tag] : (tags[tag] = [])).push(post);
72 | });
73 | else post.tags = [];
74 | });
75 | return tags;
76 | }
77 |
78 | var defaults = {
79 | postLink: "${name}.html"
80 | };
81 |
82 | function readConfig() {
83 | var config = (util.exists("_config.yml") && yaml.load(fs.readFileSync("_config.yml", "utf8"))) || {};
84 | for (var opt in defaults) if (defaults.hasOwnProperty(opt) && !config.hasOwnProperty(opt))
85 | config[opt] = defaults[opt];
86 | return config;
87 | }
88 |
89 | function getURL(config, post) {
90 | var link = config.postLink;
91 | for (var prop in post) link = link.replace("${" + prop + "}", post[prop]);
92 | return link;
93 | }
94 |
95 | function ensureDirectories(path) {
96 | var parts = path.split("/"), cur = "";
97 | for (var i = 0; i < parts.length - 1; ++i) {
98 | cur += parts[i] + "/";
99 | if (!util.exists(cur, true)) fs.mkdirSync(cur);
100 | }
101 | }
102 |
103 | function prepareIncludes(ctx) {
104 | if (!util.exists("_includes/", true)) return;
105 | fs.readdirSync("_includes/").forEach(function(file) {
106 | Mold.define(file.match(/^(.*?)\.[^\.]+$/)[1],
107 | Mold.bake(fs.readFileSync("_includes/" + file, "utf8"), ctx));
108 | });
109 | }
110 |
111 | var layouts = {};
112 | function getLayout(name, ctx) {
113 | if (name.indexOf(".") == -1) name = name + ".html";
114 | if (layouts.hasOwnProperty(name)) return layouts[name];
115 | var tmpl = Mold.bake(fs.readFileSync("_layouts/" + name, "utf8"), ctx);
116 | tmpl.filename = name;
117 | layouts[name] = tmpl;
118 | return tmpl;
119 | }
120 |
121 | function generate() {
122 | var config = readConfig(), posts = readPosts(config);
123 | var ctx = {site: {posts: posts, tags: gatherTags(posts), config: config},
124 | dateFormat: require("dateformat")};
125 | prepareIncludes(ctx);
126 | if (util.exists("_site", true)) rmrf.sync("_site");
127 | posts.forEach(function(post) {
128 | if (post.isLink) return;
129 | var path = "_site/" + post.url;
130 | ensureDirectories(path);
131 | fs.writeFileSync(path, getLayout(post.layout || "post.html", ctx)(post), "utf8");
132 | });
133 | function walkDir(dir) {
134 | fs.readdirSync(dir).forEach(function(fname) {
135 | if (/^[_\.]/.test(fname)) return;
136 | var file = dir + fname;
137 | if (fs.statSync(file).isDirectory()) {
138 | walkDir(file + "/");
139 | } else {
140 | var out = "_site/" + file;
141 | ensureDirectories(out);
142 | if (/\.md$/.test(fname) && hasFrontMatter(file)) {
143 | var split = readFrontMatter(fs.readFileSync(file, "utf8"));
144 | var doc = split.front;
145 | var layout = getLayout(doc.layout || "default.html", ctx);
146 | doc.content = marked(split.main);
147 | doc.name = fname.match(/^(.*?)\.[^\.]+$/)[1];
148 | doc.url = file;
149 | out = out.replace(/\.md$/, layout.filename.match(/(\.\w+|)$/)[1]);
150 | fs.writeFileSync(out, layout(doc), "utf8");
151 | } else {
152 | util.copyFileSync(file, out);
153 | }
154 | }
155 | });
156 | }
157 | walkDir("./");
158 | }
159 |
160 | generate();
161 |
162 | // Long line
163 | function highlightCode2(code, lang) { if (!lang) return code; if (!CodeMirror.modes.hasOwnProperty(lang)) { try { require("codemirror/mode/" + lang + "/" + lang); } catch(e) { console.log(e.toString());CodeMirror.modes[lang] = false; } } if (CodeMirror.modes[lang]) { var html = ""; CodeMirror.runMode(code, lang, function(token, style) { if (style) html += "" + Mold.escapeHTML(token) + " "; else html += Mold.escapeHTML(token); }); return html; } else return code; } function hasFrontMatter2(file) { var fd = fs.openSync(file, "r"); var b = new Buffer(4); var ret = fs.readSync(fd, b, 0, 4, 0) == 4 && b.toString() == "---\n"; fs.closeSync(fd); return ret; } function readFrontMatter2(file) { if (/^---\n/.test(file)) { var end = file.search(/\n---\n/); if (end != -1) return {front: yaml.load(file.slice(4, end + 1)) || {}, main: file.slice(end + 5)}; } return {front: {}, main: file}; } function readPosts2(config) { var posts = []; fs.readdirSync("_posts/").forEach(function(file) { var d = file.match(/^(\d{4})-(\d\d?)-(\d\d?)-(.+)\.(md|link)$/); var split = readFrontMatter(fs.readFileSync("_posts/" + file, "utf8")); var post = split.front; post.date = new Date(d[1], d[2] - 1, d[3]); post.name = d[4]; if (!post.tags) post.tags = []; if (!post.tags.forEach && post.tags.split) post.tags = post.tags.split(/\s+/); if (d[5] == "md") { post.content = marked(split.main); post.url = getURL(config, post); } else if (d[5] == "link") { var escd = Mold.escapeHTML(post.url); post.content = "Read this post at " + escd + " .
"; post.isLink = true; } posts.push(post); }); posts.sort(function(a, b){return b.date - a.date;}); return posts; }
164 |
--------------------------------------------------------------------------------
/test/fragments.js:
--------------------------------------------------------------------------------
1 | var util = require("./util");
2 | var tern = require("../lib/tern");
3 | var fs = require("fs");
4 |
5 | var file = fs.readFileSync(util.resolve("test/data/large.js"), "utf8");
6 |
7 | var server = new tern.Server({defs: [util.ecmascript]});
8 |
9 | var curTest;
10 | function fail(msg) { throw curTest + ": " + msg; }
11 | function eq(a, b, msg) { if (a != b) fail(msg || a + " != " + b); }
12 |
13 | exports.runTests = function(filter) {
14 | var added = false;
15 | function test(name, start, text, query, check) {
16 | name = "fragments/" + name;
17 | if (filter && name.indexOf(filter) == -1) return;
18 | if (!added) {
19 | server.request({files: [{type: "full", name: "file", text: file}]}, function(){});
20 | util.addFile();
21 | added = true;
22 | }
23 | util.addTest();
24 | curTest = name;
25 | if (typeof text == "number") text = file.slice(start, text);
26 | query.file = "#0";
27 | var fdata = {type: "part", name: "file", text: text, offset: start};
28 | server.request({files: [fdata], query: query}, function(err, data) {
29 | try {
30 | if (err) fail(err);
31 | else check(data);
32 | } catch (e) {
33 | util.failure(String(e));
34 | }
35 | });
36 | }
37 |
38 | test("simple", 864, 1065, {type: "definition", end: 59},
39 | function(data) { eq(data.start, 888); });
40 | test("only_body", 895, 1064, {type: "definition", end: 28},
41 | function(data) { eq(data.start, 888); });
42 | test("replace_body", 895, "\n file", {type: "definition", end: 7},
43 | function(data) { eq(data.start, 888); });
44 |
45 | test("long_line", 6141, 6774, {type: "type", end: 603},
46 | function(data) { eq(data.type, "bool"); });
47 | test("long_line_replace", 6141, "var x = 'hi'; x;", {type: "type", end: 15},
48 | function(data) { eq(data.type, "string"); });
49 |
50 | test("redefine", 2444, "var defaults = 900; // and a long comment to cover the whole exprssion\n",
51 | {type: "type", end: 0, variable: "defaults"},
52 | function(data) { eq(data.type, "number"); });
53 |
54 | test("find_def_in_fragment", 3420, file.slice(3424, 5103),
55 | {type: "definition", end: 1280},
56 | function(data) { eq(data.start, 3429); });
57 | };
58 |
--------------------------------------------------------------------------------
/test/reload.js:
--------------------------------------------------------------------------------
1 | var tern = require("../lib/tern");
2 | var util = require("./util");
3 |
4 | var tests = [], added = false;
5 | function test(name, f) {
6 | tests.push(function(filter) {
7 | if (filter && name.indexOf(filter) == -1) return;
8 | if (!added) { util.addFile(); added = true; }
9 | util.addTest();
10 |
11 | f(new tern.Server({defs: [util.ecmascript], debug: true}));
12 | });
13 | }
14 |
15 | exports.runTests = function(filter) {
16 | tests.forEach(function(test) { test(filter); });
17 | };
18 |
19 | test("reloadCall", function(server) {
20 | server.addFile("call.js", "myfun('2');");
21 | server.addFile("fun.js", "function myfun(x) {\n x;\n}");
22 | server.flush(function() {
23 | var query = {files: [{name: "fun.js", type: "full", text: "function myfun(xy) {\n xy;\n}"}],
24 | query: {type: "type", end: {line: 1, ch: 4}, file: "fun.js"}};
25 | server.request(query, function(err, data) {
26 | if (err) return util.failure(err);
27 | if (data.type != "string") util.failure("reloadCall: Reloading function cleared argument type");
28 | });
29 | });
30 | });
31 |
32 | test("reloadProps", function(server) {
33 | server.addFile("obj.js", "var o = {};\no.id = 1234;\no.name = 'test';");
34 | server.flush(function() {
35 | var query = {files: [{name: "obj.js", type: "full", text: "var o = {};\no.kapow = 1234;\no.name = 'test';\no."}],
36 | query: {type: "completions", end: {line: 3, ch: 2}, file: "obj.js"}};
37 | server.request(query, function(err, data) {
38 | if (err) return util.failure(err);
39 | var compls = data.completions;
40 | compls.sort();
41 | if (compls.join() != "kapow,name") util.failure("reloadProps: Reloading properties failed (" + compls + ")");
42 | });
43 | });
44 | });
45 |
46 | test("reloadVar", function(server) {
47 | server.addFile("a.js", "var x = 1;");
48 | server.flush(function() {
49 | server.request({files: [{name: "a.js", type: "full", text: "var x = 'hi';"}],
50 | query: {type: "type", end: {line: 0, ch: 5}, file: "a.js"}}, function(err, data) {
51 |
52 | if (err) return util.failure(err);
53 | if (data.type != "string")
54 | util.failure("reloadVar: var did not get new string type (" + data.type + ")");
55 | });
56 | });
57 | });
58 |
59 | test("reloadForeignProp", function(server) {
60 | server.addFile("a.js", "Date.foo = 100;");
61 | server.flush(function() {
62 | server.request({files: [{name: "a.js", type: "full", text: "Date.foo"}],
63 | query: {type: "type", end: {line: 0, ch: 8}, file: "a.js"}}, function(err, data) {
64 | if (err) return util.failure(err);
65 | if (data.type != "?")
66 | util.failure("reloadForeignProp: reload did not clear Date.foo (" + data.type + ")");
67 | });
68 | });
69 | });
70 |
71 | test("reloadCalledForeignProp", function(server) {
72 | server.addFile("a.js", "Date.foo = function(a) { return a; };");
73 | server.addFile("b.js", "Date.foo('hi');");
74 | server.flush(function() {
75 | server.request({files: [{name: "a.js", type: "full", text: "Date.foo = function(a) { return a + 1; };"}],
76 | query: {type: "type", end: {line: 0, ch: 33}, file: "a.js"}}, function(err, data) {
77 | if (err) return util.failure(err);
78 | if (data.type != "string")
79 | util.failure("reloadCalledForeignProp: reload cleared argument type for Date.foo (" + data.type + ")");
80 | });
81 | });
82 | });
83 |
84 | test("reloadDelFile", function(server) {
85 | server.addFile("a.js", "function foobar() { return 10; }");
86 | server.flush(function() {
87 | server.delFile("a.js");
88 | server.request({files: [{name: "b.js", type: "full", text: "foobar"}],
89 | query: {type: "type", end: {line: 0, ch: 6}, file: "b.js"}}, function(err, data) {
90 | if (err) return util.failure(err);
91 | if (data.type != "?")
92 | util.failure("reloadDelFile: deleting a file did not clear the variable it created (" + data.type + ")");
93 | });
94 | });
95 | });
96 |
--------------------------------------------------------------------------------
/test/runcases.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs"), path = require("path");
2 | var infer = require("../lib/infer");
3 | var tern = require("../lib/tern");
4 | var acorn = require("acorn");
5 | var walk = require("acorn-walk");
6 | require("../plugin/requirejs.js");
7 | require("../plugin/node.js");
8 | require("../plugin/es_modules.js");
9 | require("../plugin/doc_comment.js");
10 | require("../plugin/angular.js");
11 | require("../plugin/complete_strings.js");
12 | require("../plugin/webpack.js");
13 | var util = require("./util");
14 |
15 | var defData = {
16 | browser: util.browser,
17 | jquery: util.jquery,
18 | underscore: util.underscore
19 | };
20 |
21 | function getDefs(text) {
22 | var spec = /\/\/ environment=(\w+)\n/g, m, defs = [util.ecmascript];
23 | while (m = spec.exec(text)) {
24 | var data = defData[m[1]];
25 | if (!data) throw new Error("Unknown environment: " + m[1]);
26 | defs.push(data);
27 | }
28 | return defs;
29 | }
30 |
31 | function getPlugins(text) {
32 | var spec = /\/\/ plugin=(\w+)(?: (.*))?\n/g, m, plugins = {doc_comment: true};
33 | while (m = spec.exec(text)) {
34 | if (m[2]) {
35 | var options = JSON.parse(m[2]);
36 | if (options)
37 | plugins[m[1]] = options;
38 | else
39 | delete plugins[m[1]];
40 | } else {
41 | plugins[m[1]] = {};
42 | if (m[1] == "node") plugins.modules = {modules: nodeModules};
43 | }
44 | }
45 | return plugins;
46 | }
47 |
48 | fs.readdirSync(util.resolve("test/cases/defs")).forEach(function(name) {
49 | if (/\.json$/.test(name))
50 | defData[path.basename(name, ".json")] =
51 | JSON.parse(fs.readFileSync(util.resolve("test/cases/defs/" + name), "utf8"));
52 | });
53 |
54 | var nodeModules = {};
55 | fs.readdirSync(util.resolve("test/cases/node_modules")).forEach(function(name) {
56 | if (/\.json$/.test(name))
57 | nodeModules[path.basename(name, ".json")] =
58 | JSON.parse(fs.readFileSync(util.resolve("test/cases/node_modules/" + name), "utf8"));
59 | });
60 |
61 | function serverOptions(context, text) {
62 | return {
63 | defs: getDefs(text),
64 | getFile: function(name) { return fs.readFileSync(path.resolve(context, name), "utf8"); },
65 | debug: true,
66 | projectDir: context,
67 | plugins: getPlugins(text)
68 | };
69 | }
70 |
71 | exports.runTests = function(filter, caseDir) {
72 | caseDir = caseDir || util.resolve("test/cases");
73 | fs.readdirSync(caseDir).forEach(function(name) {
74 | if (filter && name.indexOf(filter) == -1) return;
75 |
76 | var fname = name, context = caseDir;
77 | if (fs.statSync(path.resolve(context, name)).isDirectory()) {
78 | if (name == "node_modules" || name == "defs") return;
79 | context = path.join(context, name);
80 | fname = "main.js";
81 | }
82 | if (!/\.js$/.test(fname)) return;
83 | util.addFile();
84 |
85 | var text = fs.readFileSync(path.join(context, fname), "utf8"), m;
86 | var server = new tern.Server(serverOptions(context, text));
87 | server.addFile(fname);
88 | var ast = server.files[0].ast;
89 |
90 | if (m = text.match(/\/\/ loadfiles=\s*(.*)\s*\n/))
91 | m[1].split(/,\s*/g).forEach(function(f) {server.addFile(f);});
92 |
93 | var typedef = /\/\/(<)?(\+\??|:\?|::?|doc\+?:|loc:|refs:|origin:|exports:) *([^\r\n]*)/g;
94 | function fail(m, str) {
95 | util.failure(name + ", line " + acorn.getLineInfo(text, m.index).line + ": " + str);
96 | }
97 |
98 | while (m = typedef.exec(text)) (function(m) {
99 | var args = m[3], kind = m[2], directlyHere = m[1];
100 | util.addTest();
101 | if (kind == "+" || kind == "+?") { // Completion test
102 | var columnInfo = /\s*@(\d+)$/.exec(args), pos = m.index;
103 | if (columnInfo) {
104 | var line = acorn.getLineInfo(text, m.index).line;
105 | pos = {line: line - 1, ch: Number(columnInfo[1]) - 1};
106 | args = args.slice(0, columnInfo.index);
107 | } else {
108 | while (/[\s;]/.test(text.charAt(pos - 1))) --pos;
109 | if (/['"]/.test(text.charAt(pos - 1))) --pos;
110 | }
111 | var query = {type: "completions", end: pos, file: fname, guess: kind == "+?"};
112 | var andOthers = /,\s*\.\.\.$/.test(args);
113 | if (andOthers) args = args.slice(0, args.lastIndexOf(","));
114 | var parts = args ? args.split(/\s*,\s*/) : [];
115 | server.request({query: query}, function(err, resp) {
116 | if (err) throw err;
117 | var match = andOthers || parts.length == resp.completions.length;
118 | for (var i = 0; i < parts.length && match; ++i)
119 | if (resp.completions.indexOf(parts[i]) < 0) match = false;
120 | if (!match)
121 | fail(m, "Completion set failed at hint: " + parts[i - 1] +
122 | "\n got: " + resp.completions.join(", ") + "\n wanted: " + args);
123 | });
124 | } else if (kind == "exports:") {
125 | server.request({query: {type: "exports", file: fname}}, function(err, resp) {
126 | if (err) throw err;
127 | if (resp.type != args) fail(m, "Export type failed. Got:\n " + resp.type + "\nwanted:\n " + args);
128 | });
129 | } else {
130 | var start, end;
131 | if (directlyHere) {
132 | for (end = m.index; end && /[\s:,;]/.test(text.charAt(end - 1)); --end) {}
133 | start = null;
134 | } else {
135 | var expr = walk.findNodeBefore(ast, m.index, "Expression");
136 | if (!expr) {
137 | fail(m, "No expresion found");
138 | return;
139 | }
140 | start = expr.node.start; end = expr.node.end;
141 | }
142 | var query = {type: /doc/.test(kind) ? "documentation" : kind == "loc:" ? "definition" : kind == "refs:" ? "refs" : "type",
143 | start: start, end: end,
144 | docFormat: kind == "doc+:" ? "full" : null,
145 | file: fname,
146 | depth: kind == "::" ? 5 : null,
147 | lineCharPositions: true};
148 | server.request({query: query}, function(err, resp) {
149 | if (err) throw err;
150 |
151 | if (/doc/.test(kind)) { // Docstring test
152 | var expected = args.replace(/\\n/g, "\n");
153 | if (resp.doc != expected) {
154 | fail(m, "Found " + (resp.doc ? "docstring\n " + resp.doc + "\n" : "no docstring ") +
155 | "instead of expected docstring\n " + expected);
156 | }
157 | } else if (kind == "loc:") { // Definition finding test
158 | var pos = args.match(/^\s*(\d+),\s*(\d+)(?:,\s*([^,]+))?/), line = Number(pos[1]), col = Number(pos[2]), file = pos[3];
159 | var actualLoc = (file ? resp.origin + ":" : "") + (resp.start.line + 1) + ":" + resp.start.ch;
160 | var expectedLoc = (file ? file + ":" : "") + line + ":" + col;
161 | if (!resp.start)
162 | fail(m, "Did not find a definition (expected " + expectedLoc + ").");
163 | else if (resp.start.line + 1 != line || resp.start.ch != col || (file && file !== resp.origin))
164 | fail(m, "Found definition at " + actualLoc +
165 | " instead of expected " + expectedLoc);
166 | } else if (kind == "origin:") { // Origin finding test
167 | if (resp.origin != args)
168 | fail(m, "Found origin\n " + resp.origin + "\ninstead of expected origin\n " + args);
169 | } else if (kind == "refs:") { // Reference finding test
170 | var pos = /\s*(\d+),\s*(\d+)/g, mm;
171 | while (mm = pos.exec(args)) {
172 | var line = Number(mm[1]), col = Number(mm[2]), found = false;
173 | for (var i = 0; i < resp.refs.length; ++i) {
174 | var ref = resp.refs[i];
175 | if (ref.start.line + 1 == line && ref.start.ch == col) { found = true; break; }
176 | }
177 | if (!found) fail(m, "Did not find reference at line " + line + ", column " + col + ".");
178 | }
179 | } else { // Type test
180 | var type = resp.guess && kind != ":?" ? "?" : resp.type || "?";
181 | if (type != args)
182 | fail(m, "Expression has type\n " + type + "\ninstead of expected type\n " + args);
183 | }
184 | });
185 | }
186 | })(m);
187 | });
188 | };
189 |
--------------------------------------------------------------------------------
/test/timeout.js:
--------------------------------------------------------------------------------
1 | var tern = require("../lib/tern");
2 | var infer = require("../lib/infer");
3 | var util = require("./util");
4 | var fs = require("fs");
5 |
6 | exports.runTests = function(filter) {
7 | if (filter && "timeout".indexOf(filter) == -1) return;
8 |
9 | util.addFile();
10 | util.addTest();
11 | var server = new tern.Server({});
12 | var file = fs.readFileSync(util.resolve("lib/infer.js"), "utf8");
13 | try {
14 | server.request({timeout: 10,
15 | files: [{type: "full", name: "infer.js", text: file}],
16 | query: {type: "type", end: 0, file: "infer.js"}}, function(err, result) {
17 | if (!err || !(err instanceof infer.TimedOut))
18 | util.failure("timeout: failed to time out");
19 | });
20 | } catch(e) {
21 | util.failure("timeout: exception thrown: " + e.stack);
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/test/util.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs"), path = require("path");
2 |
3 | var projectDir = path.resolve(__dirname, "..");
4 | exports.resolve = function(pth) { return path.resolve(projectDir, pth); };
5 |
6 | exports.ecmascript = JSON.parse(fs.readFileSync(exports.resolve("defs/ecmascript.json")), "utf8");
7 | exports.browser = JSON.parse(fs.readFileSync(exports.resolve("defs/browser.json")), "utf8");
8 | exports.jquery = JSON.parse(fs.readFileSync(exports.resolve("defs/jquery.json")), "utf8");
9 | exports.underscore = JSON.parse(fs.readFileSync(exports.resolve("defs/underscore.json")), "utf8");
10 |
11 | var files = 0, tests = 0, failed = 0;
12 |
13 | exports.addFile = function() { ++files; };
14 | exports.addTest = function() { ++tests; };
15 |
16 | exports.failure = function(message) {
17 | console.log(message);
18 | ++failed;
19 | };
20 |
21 | exports.hasFailed = function() { return failed > 0; };
22 |
23 | process.on("exit", function() {
24 | console.log("Ran " + tests + " tests from " + files + " files.");
25 | console.log(failed ? failed + " failures!" : "All passed.");
26 | });
27 |
--------------------------------------------------------------------------------