google / tern-closure Goto Github PK
View Code? Open in Web Editor NEWA Tern plugin adding Closure support.
License: Apache License 2.0
A Tern plugin adding Closure support.
License: Apache License 2.0
goog.module is a new way of organizing Closure JS files.
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)
Example:
/** @type {{prop1: Prop1Type, prop2: Prop2Type}} */
var recordTypeExpr;
recordTypeExpr; //: {prop1: Prop1Type, prop2: Prop2Type}
Example:
/** @type {(MyClass|YourClass)} */
var union;
union; //: (MyClass|YourClass)
More importantly, we want proper autocompletion of properties on all types in the union.
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.
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.
It should be cool if tern closure provides completion for namespaces+classes inside goog.require( )
tern provides hook for completion. I have done a PR for node module completion in ternjs/tern#348
It should be cool if you can study it and do the same thing for closure and improve too my PR.
Example:
/** @type {?string} */
var nullable;
nullable;//: ?string
/** @type {!MyClass} */
var nonNullable;
nonNullable;//: !MyClass
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.
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.
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.
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).
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.
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.
The current implementation of inheritance doesn't support multiple inheritance at all, though multiple inheritance is possible for interfaces.
I don't know what's necessary to set up tern-closure with tern.java, but instructions for setup with tern.java should be included in INSTALL.md.
@angelozerr, how does that setup work?
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?
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.
I create just this issue for Eclipse users which wishes to use tern-closure inside Eclipse IDE. See https://github.com/angelozerr/tern.java/wiki/Tern-&-Closure-support for more information.
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:
goog.require
classes in the current file.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).
For your information, I have started tern lint https://github.com/angelozerr/tern.lint
You can validate too custom validation, like goog.require('classWichDoesn'tExists
I will happy to explain you how it works and we could discuss too how to improve it.
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.
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?
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.
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()
Example:
/** @typedef {{numProp: number}} */
var TypeDefType;
/** @type {TypeDefType} */
var typeDefVar;
typeDefVar; //: TypeDefType
typeDefVar.numProp; //: number
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.
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.
goog.scope
allows the aliasing of namespaces. We should handle type annotations with namespaces aliased by goog.scope
.
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.
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
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).
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.