Git Product home page Git Product logo

tern-closure's Introduction

tern-closure

tern-closure is a plugin which adds support for Closure Compiler annotations and the Closure type system to the JavaSript code intelligence system Tern.

To use tern-closure, you need to install it and then configure Tern to load it.

Features

tern-closure adds the following features to your Tern installation:

  1. Understanding of types in JSDoc type annotations (similar to the doc_comment plugin included with Tern).
  2. Understanding of inheritance and interfaces with @extends and @implements.
  3. Completion and go-to-definition support for type names in JSDoc comments and in strings (e.g. @type annotations and goog.require arguments).
  4. Automatic loading of the definitions for types, so that you get completion and type information from other files and can jump to definitions in those files. This requires enabling a finder. We consider access modifiers and how types are used in order to load only the types relevant the files you are editing, keeping this feature feasible even for large projects.

Installation

Currently, tern-closure only works with the NodeJS Tern Server, and not within a browser.

Short version

After installing Tern according the setup instructions of your desired editor plugin, go to the place where the Tern package was installed (or the Tern repo was cloned) and run

$ npm install tern-closure

Or, if you're not sure where Tern was installed, you can try

$ npm install -g tern-closure

Long version

See INSTALL.md for instructions tailored to each editor.

Configuration

In order for Tern to load the tern-closure plugin once it is installed, you must include closure in the plugins section of your Tern configuration file. The configuration file can be either a file named .tern-project in your project's root directory, or .tern-config in your home directory.

You must also explicitly disable the default doc_comment plugin, which will interfere with tern-closure.

Here is a minimal example .tern-project configuration file:

{
  "plugins": {
    "doc_comment": false,
    "closure": {}
  }
}

"Project directory" and .tern-project vs .tern-config

Tern looks for .tern-project first, walking up the directory tree, and uses its location as the "project directory". If no .tern-project is found, your .tern-config is loaded instead, and the working directory of the Tern server process is used as the "project directory".

Since Tern and tern-closure (including finders like grep) use the "project directory" as the base for all relative paths, you should either use .tern-project or be careful about where you start your Tern server (or, where your editor plugin starts your Tern server).

Options

You can set the following options in the closure section of your Tern configuration file:

  • finder Object. Configuration for finding the files that provide types. See Finders below. Optional. Default: None.
  • debug boolean. Whether tern-closure should print debug output. Optional. Default: Match Tern debug option.
  • noMinimalLoad boolean. When a finder is active, this disables attempts to limit loaded files according to visibility. This is mostly for debugging - if setting this fixes an issue, file a bug. Optional. Default: false.

Finders

tern-closure uses "finders" to find the files providing Closure names via goog.provide. Finders allow tern-closure to load and interpret the files providing names required via goog.require or referenced in JSDoc type strings so it better understands the context of a given file.

The finder section of the options object for closure in your .tern-project file specifies what finder implementation you want to use, and what options you want to pass to the finder. By default, no finder is used, and files are not automatically loaded. Currently, only one finder implementation is included with tern-closure, grep.

Common finder options:

  • name The name of the finder you want to use. Required.
  • debug Whether the finder should print debug output. Optional. Default: Match tern-closure debug option.

grep

This is a basic finder which uses the grep command-line utility (or findstr in Windows) to search for goog.provide statements at startup and create a map of Closure names to providing files.

Options:

  • dirs An array of path strings indicating which directories to search for files. Paths can either be absolute, or relative to the project directory. Optional. Default: ['.'] (just the project directory).

Here is an example .tern-project file using the grep finder:

{
  "plugins": {
    "doc_comment": false,
    "closure": {
      "finder": {
        "name": "grep",
        "dirs": [
          "relevant/project/subdir",
          "/absolute/path/to/library"
        ]
      }
    }
  }
}

Additional finders

You can easily use a finder not included in this repository, or implement your own. This allows you to search for names in different ways, on demand, and to use existing indexes of your codebase.

Given a finder name name, tern-closure first looks in its own lib/finder directory, then attempts to load name using require(), so a third-party finder module can be installed as an npm package.

A finder module must implement a simple interface:

  • It must export a constructor function(projectDir: string, options: Object) which takes the project directory and an options object as parameters. Options are specified in the Tern configuration file.

  • Instances of that constructor must have a method findFile(name: string, cb: function(file: string)), which takes as arguments a Closure name name to find and a callback function cb to call with the path to file providing name. cb should be called asynchronously, even if the providing file is known when findFile is called. This allows finders to execute I/O operations to find files on demand.

Please note that while tern-closure is in a 0.X.X release, the finder API may be subject to breaking changes.

Bug reports and feature requests

Please file bug reports and feature requests as issues on the issues page of the tern-closure repository.

Contributing

Pull requests to tern-closure are welcome. Please see the CONTRIBUTING.md file for requirements and guidelines.

Disclaimer: tern-closure is not an official Google product, and is maintained on a best-effort basis.

tern-closure's People

Contributors

angelozerr avatar jgiles avatar metamemoryt avatar mtaran-google avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

tern-closure's Issues

Support generics

The Closure compiler supports generics, like

/**
 * @constructor
 * @template T
 */
Foo = function() { ... };

A good experience with generics might require support for casting (#12), but we might get things working decently without it.

At a minimum, we should stop trying and failing to find and import the files providing template types.

Stop depending on dev Doctrine

Currently, we depend on latest version of Doctrine at HEAD (see package.json). We should probably depend on some version number instead.

This is because we rely on the fix to an issue parsing access tags with types, and the fix is not yet in a published release.

@Constellation, do you know when you plan to publish a new release of Doctrine?

Add an native Node search finder

Currently, the the only finder (grep) depends on the presence of platform-specific utilities (grep in *Nix, and soon findstr in Windows).

There should be a pure-Node finder, for maximum portability.

Only process JSDoc-form comments

The Tern comment-finding code looks for both
/** JSDoc comment form */
and
// Single line comment form

Since we assume comments without any type information are for methods without return or parameter values, this means statements like

// This is an assignment.
var a = b;

can end up with a being assigned the type fn()

Support union types

Example:

/** @type {(MyClass|YourClass)} */
var union;
union; //: (MyClass|YourClass)

More importantly, we want proper autocompletion of properties on all types in the union.

Record type support

Example:

/** @type {{prop1: Prop1Type, prop2: Prop2Type}} */
var recordTypeExpr;
recordTypeExpr; //: {prop1: Prop1Type, prop2: Prop2Type}

grep finder does not handle multiline goog.provide statments

In the case of deep namespaces and long class names, goog.provide statements are sometimes broken across lines:

goog.provide(
    'this.is.a.very.very.very.very.long.ClassNameThatNeedsWrapping');

The grep finder currently just drops these. Addressing this issue across all platforms (without introducing a dependency on less-common options or utilities) would be difficult, so this will likely be left unfixed.

The upcoming native Node search finder (#5) should handle this case.

tern-closure and atom-tern

So I tried to setup tern-closure in atom on top of the atom-tern.

Since there is no package available I npm install tern-closure in
~/.atom/packages/atom-ternjs/node-modules/tern/
This installs the tern-closure into
~/.atom/packages/atom-ternjs/node-modules/tern/node-modules/tern-closure

My tern-project looks like this:

{
"ecmaVersion": 6,
"libs": [
"browser",
"jquery"
],
"loadEagerly": [
"./src/vcs/vcm/*/.js"
],
"plugins": {
"complete_strings": {},
"node": {},
"lint": {},
"angular": {},
"requirejs": {},
"es_modules": {},
"doc_comment": false,
"closure" : {}
}
}

However, immediately the errors are thrown:

atom-ternjs
C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\closure.js:292 return node.right.body.scope.fnType; ^

TypeError: Cannot read property 'fnType' of undefined at getFnType (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\closure.js:292:33) at interpretComments (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\closure.js:216:18) at walk.simple.AssignmentExpression (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\closure.js:172:7) at c (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\node_modules\acorn\util\walk.js:30:18) at Object.skipThrough (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\acorn\dist\walk.js:168:3) at c (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\node_modules\acorn\util\walk.js:29:17) at Object.base.ExpressionStatement.base.ParenthesizedExpression (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\acorn\dist\walk.js:185:10) at c (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\node_modules\acorn\util\walk.js:29:17) at Object.exports.searchVisitor.walk.make.Statement (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\lib\infer.js:1929:7) at c (C:\Users\lvanwalstijn.atom\packages\atom-ternjs\node_modules\tern\node_modules\tern-closure\node_modules\acorn\util\walk.js:29:17)

AND

tern exited with code: 1.
Restart the server via Packages -> Atom Ternjs -> Restart server

Any ideas?

TypeError: Cannot read property 'name' of null

was trying to parse this file: https://gist.github.com/MetaMemoryT/e9b98d89c62ec7aec5a1

and got an error that was not very descriptive

it would be nice if it would tell what line of the input file it failed at

$ /c/nodejs/node_modules/tern/bin/condense --name "sqljs-substring" --plugin /c/Users/Sean/s/eclipse-luna/eclipse-standard-luna-R-win32-x86_64/eclipse/plugins/tern.core_ 0.6.0.201409182110/node_modules/tern/node_modules/tern-closure/closure.js --def helpers.json sql.js/coffee/api.js > sqljs-substring.json
C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\node_modules\doctrine\doctrine.js:1761
                    if (isParamTitle(this._title) && this._tag.type.name) {
                                                                   ^
TypeError: Cannot read property 'name' of null
    at TagParser.parseName (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\node_modules\doctrine\doctrine.js:1761:68)
    at TagParser.parse (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\node_modules\doctrine\doctrine.js:1976:34)
    at parseTag (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\node_modules\doctrine\doctrine.js:1999:27)
    at Object.parse (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\node_modules\doctrine\doctrine.js:2071:23)
    at Comment.parse (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\lib\comment.js:40:26)
    at interpretComments (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\closure.js:209:11)
    at walk.simple.AssignmentExpression (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\tern-closure\closure.js:172:7)
    at c (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\acorn\util\walk.js:30:18)
    at Object.skipThrough (C:\nodejs\node_modules\tern\node_modules\acorn\util\walk.js:163:39)
    at c (C:\Users\Sean\s\eclipse-luna\eclipse-standard-luna-R-win32-x86_64\eclipse\plugins\tern.core_0.6.0.201409182110\node_modules\tern\node_modules\acorn\util\walk.js:29:17)

Stop depending on Node as the environment

tern-closure should not work only when run under Node. It should run anywhere that Tern can. In particular, it should run in the browser.

On some level, this probably just involves wrapping each module in an IIFE with a bit of boilerplate like Tern. However, it might also motivate some code re-organization.

Interface multiple inheritance

The current implementation of inheritance doesn't support multiple inheritance at all, though multiple inheritance is possible for interfaces.

Function type expression support

Example:

/** @type {function(ParamType): ReturnType} */
var fnTypeExpr;
fnTypeExpr; //: function(ParamType) -> ReturnType

Note that Tern normally outputs parameter names in its type strings, and parameter names are generally not included in function type expressions. We may end up needing to invent names (a, b, etc).

Support casting

We should add support for casting:

/** @type {Object} */
var genericObject;
var castObject = /** @type {CastClass} */ (genericObject);
castObject; //: CastClass

Right now, castObject has type {}.

This will be tricky, since it will definitely involve changing the way we attach JSDoc comments to AST nodes.

Minimal requirements loading

Currently, we try to load files for all the referenced types in all the files we process, including those that we are loading automatically from other files. This means that for anything other than smallish projects, we just keep loading files until Tern's dependency budget system cuts us off.

This is a problem because many of the loaded files are not actually necessary for understanding the current file. By loading unnecessary files, we are bloating memory consumption and slowing things down. We could even end up consuming the dependency budget on unneeded files and preventing the processing of something that actually matters.

It seems like we should only need to load:

  1. goog.require classes in the current file.
  2. Types referenced in type annotations in the current file.
  3. Any types we could obtain from the above types (return types of their methods).
    • Recurse.
  4. Superclasses of all of the above.
    • Recurse

Include condensed type definition file of Closure library

We should include a JSON type definition file for the contents of the Closure library, and optionally load that definition according to a configuration setting.

The file could be rather large - it's possible we would need to settle for a subset, or break up the library into chunks.

There could be some trickiness to encoding all the type information we are interested in, since some aspects of the Closure type system (inheritance, unions, etc) are not explicitly supported as part of Tern.

Support varargs

Example:

/** @param {...ParamType} var_args */
var fnVarArgs = function(var_args) {
  arguments; //: [ParamType]
  var_args; //: ...ParamType
};
fnVarArgs; //: fn(var_args: ...ParamType)

This will always be a bit of a hack because we'd have to apply the varargs type to the entire arguments variable, but it would be serviceable.

Go-to-overriden-method

We should provide an easy way to jump to an overriden method from the overriding method.

Though we could add this as a new type of request, it would be much better to do it in a client-independent manner. The easiest way to do this would probably be to catch go-to-definition calls in @override annotations, much like we want to within type strings (#28).

A definition request with a location inside an @override tag would return the definition location of the method up the prototype chain of the class.

tern-closure requires version of tern too old

The default installation instructions no longer work: tern is 0.11 as of late and tern-closure is still with 0.7 and the installation must be reverted and tailored to satisfy this.

Support goog.scope

goog.scope allows the aliasing of namespaces. We should handle type annotations with namespaces aliased by goog.scope.

Include Closure base.js definitions

While it may not make sense to condense the whole Closure library and include its definition (#23), we should at a minimum include definitions for things declared in Closure's base.js.

Aside from being commonly used, since there is no goog.provide('goog') or goog.require('goog'), the various goog.* methods and attributes are never loaded automatically.

Issues with JSDoc types missing braces.

The Closure compiler apparently accepts JSDoc like this:

/**
 * Immutable empty node list.
 * @constructor
 * @extends goog.ds.BasicNodeList
 */
goog.ds.EmptyNodeList = function() {

Example taken from the annotation documentation

goog.ds.BasicNodeList is not contained in braces.

Doctrine doesn't seem to like this, and does not populate the type field for that extends tag.

Verbose option to enable debug logging

tern-closure should take a 'deubg' or 'verbose' option, defaulting to match the Tern server option.

Finders should also get this option (defaulting to match the tern-closure setting).

Flatten .tern-project options structure?

Currently, finder options have their own field:

{
  "plugins": {
    "doc_comment": false,
    "closure": {
      "finder": {
        "name": "grep",
        "options": {
          "dirs": [
            "relevant/project/subdir",
            "/absolute/path/to/library"
          ]
        }
      }
    }
  }
}

It's a minor issue, but this adds extra depth to the options JSON and makes it more difficult for humans to edit.

It might be easier if the finder property was an object with all the finder options, like this:

{
  "plugins": {
    "doc_comment": false,
    "closure": {
      "finder": {
        "name": "grep",
        "dirs": [
          "relevant/project/subdir",
          "/absolute/path/to/library"
        ]
      }
    }
  }
}

A few 'options' would always be present, like name and possibly debug (#6).

Support autocompletion of names in comments

Given the number of times fully-qualified names are typically typed in JSDoc tags, it would be helpful if we could provide completions within comments.

This does not work currently, because Tern does not process the contents of comments. However, we can use Tern's completion hooks to provide our own completions (for names that we already know about for other reasons). See ternjs/tern@31f9282, and the similar issue for completions in goog.require #3.

Support optional argument types

Example:

/** @param {ParamType=} opt_param */
var fnOptParam = function(opt_param) {
  opt_param; //: ParamType=
};
fnOptParam; //: fn(opt_param: ParamType=)

Note: This is separate from nullability information.
The Tern doc_comment plugin modifies the displayed parameter names in order to surface this information. Ideally, it would be part of the type information attached to the parameter.

Completion for object litteral

Even if tern doesn't support completion for object litteral (see issue 311), I create this issue because tern-closure needs that too.

For instance you can write this JS :

var newHeader = goog.dom.createDom('h1', {'style': 'background-color:#EEE'},
    'Hello world!');

It should be very cool if we can have completion like this :

var newHeader = goog.dom.createDom('h1', {'s // here Ctrl+Space shows 'style'

and :

var newHeader = goog.dom.createDom('h1', {'style': 'back // here Ctrl+Space shows background-color

typedef support

Example:

/** @typedef {{numProp: number}} */
var TypeDefType;
/** @type {TypeDefType} */
var typeDefVar;
typeDefVar; //: TypeDefType
typeDefVar.numProp; //: number

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.