This Bugzilla instance is deprecated, and most Eclipse projects now use GitHub or Eclipse GitLab. Please see the deprecation plan for details.
Bug 465816 - Support collecting dependencies from script blocks
Summary: Support collecting dependencies from script blocks
Status: RESOLVED FIXED
Alias: None
Product: Orion (Archived)
Classification: ECD
Component: JS Tools (show other bugs)
Version: 6.0   Edit
Hardware: All All
: P2 enhancement (vote)
Target Milestone: 10.0   Edit
Assignee: Michael Rennie CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks: 475962 475964 475965 476062 476063
  Show dependency tree
 
Reported: 2015-04-29 10:02 EDT by Michael Rennie CLA
Modified: 2015-08-27 12:03 EDT (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Rennie CLA 2015-04-29 10:02:45 EDT
Consider the following snippet:

<html>
 <script type="application/javascript" src="foo.js"></script>
</html

When we create the compilation unit from that script block we should also be collecting the dependency foo.js
Comment 1 Michael Rennie CLA 2015-05-28 12:06:36 EDT
Added the update to the compilationUnit to check for found dependencies and the API to request them
Comment 2 Steve Northover CLA 2015-06-05 17:59:13 EDT
My exact case is that I have "index.html" as the entry point for the client side JavaScript and app.js for the server.  These are the two "main" programs where execution starts.  Things not reachable from either, won't be called.

... not sure if this helps at all in the thinking ...
Comment 3 Michael Rennie CLA 2015-06-08 11:30:35 EDT
(In reply to Steve Northover from comment #2)
> My exact case is that I have "index.html" as the entry point for the client
> side JavaScript and app.js for the server.  These are the two "main"
> programs where execution starts.  Things not reachable from either, won't be
> called.
> 
> ... not sure if this helps at all in the thinking ...

Yes, this is pretty much what I was thinking - from index.html, we would collect all the *.js files referenced as dependencies and have them be reachable from the HTML context
Comment 4 Steve Northover CLA 2015-06-08 14:20:53 EDT
As per our discussion, I wouldn't mind indicating somewhere what "main" is for my web application.  For Node apps, that information is available in various files whose name escapes me at this point.
Comment 5 Steve Northover CLA 2015-08-10 12:14:38 EDT
As soon as there is something I can try, can you let me know?
Comment 6 Curtis Windatt CLA 2015-08-13 17:30:13 EDT
I have code that collects the imported scripts.  Though I imagine there is a better way, I use scriptResolver and fileClient to get the script contents to pass into Tern.  I can load the files in Tern via addFile or the files[] in the request (and I checked that Tern can find the files and walk them).

Yet it never returns the declaration for any of the variables or functions the script adds to the global scope.  I can't figure out why Tern can't find the matching type when it is in another file.  Maybe on Monday Mike can debug through Tern with me.
Comment 7 Curtis Windatt CLA 2015-08-17 16:08:12 EDT
http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=a1b9d6af8db88c4d7f8127b280a285e0771c2967
I added and updated tests and have pushed the code to collect the script dependencies.
Comment 8 Steve Northover CLA 2015-08-17 18:03:02 EDT
I'm wondering what is supposed to be working and what is not.  I am comparing minesweeper-objects on beta3 and qa and the warnings are quite different (neither seem to be working well).
Comment 9 Curtis Windatt CLA 2015-08-18 16:43:30 EDT
Here are the major issues:
1) Getting the file contents with correct parents into Tern
We could accomplish this by creating a Tern plug-in that reads HTML files and parses out the script blocks, setting up any dependencies the same way the Require plug-in does.  Alternatively we can do what I'm currently doing which is finding the script blocks client side and using the file client to load the script contents.
Related issues:
a) If you call addFile() with a parent and the file is already known to Tern without a parent, the new parent relationship is ignored.
b) If we only pass the name of the file to Tern, it will use the file client to get the contents, but that will return the entire html file, not just script blocks.

2) Script file contents and HTML script block contents are in different scopes
Tern does not treat the contents of the script file as coming from the same scope as script blocks in the html.  This is a blocking issue.  One potential solution was to look at the 'maybeProps' list, but there is no type associated with maybeProps.  Perhaps we can merge all the script contents into a single file for Tern.

3) We don't support tooling on onclick and other event attributes.
A common way to call scripts from html is using onclick attributes on elements.  We don't parse out these calls when creating the compilationunit, so you can't get contentassist/opendecl/hover to work there.  Creating a regex to parse out the attributes will be very hard to do accurately (not to mention performance).  Maybe we can do something in an HTML Tern plug-in, like Angelo does in the Browser-Extension plug-in.
Comment 10 Curtis Windatt CLA 2015-08-20 18:09:51 EDT
(In reply to Curtis Windatt from comment #9)
> 2) Script file contents and HTML script block contents are in different
> scopes
> ... Perhaps we can merge all the script
> contents into a single file for Tern.

Hacked a proof of concept for this and it is working, at least for variable declarations. I was surprised to see no noticeable delay caused by finding and loading the file contents.  However, it does not play well at all with the caching of the CU and the subsequent AST.
Comment 11 Steve Northover CLA 2015-08-21 09:57:26 EDT
> However, it does not play well at all with the caching of the CU and the subsequent AST

What fails?  It is important that we support the "plain html" case and we may be able to do this with some restrictions (ie. inline code doesn't work but JS files work).
Comment 12 Curtis Windatt CLA 2015-08-24 13:23:45 EDT
(In reply to Steve Northover from comment #11)
> > However, it does not play well at all with the caching of the CU and the subsequent AST
> 
> What fails?  It is important that we support the "plain html" case and we
> may be able to do this with some restrictions (ie. inline code doesn't work
> but JS files work).

Inline code is already working.  It is only imported scripts.  Comment #10 describes my experiment of inlining the imported scripts.  In that case the major failure is that the cuProvider, astManager and Tern all have caches of the file contents.  To inline the imported scripts I have to update the contents of all these caches at a time where I can resolve deferred to collect file contents.

The next step is do a deep dive into Tern inferencer to figure out why the separate files are in separate scopes.  If that is a bug in Tern, we can try to get it fixed in Tern.  If it is expected behaviour in Tern, maybe we can pinpoint it and work around it for this case.  Understanding the Tern inferencer is a steep learning curve.
Comment 13 Steve Northover CLA 2015-08-24 13:39:03 EDT
In particular, something like this in an HTML file:

<script src="javascript/counter.js"></script>
<script src="javascript/board.js"></script>
<script src="javascript/main.js"></script>

Why would the files already be seen by Tern?
Comment 14 Curtis Windatt CLA 2015-08-24 14:18:19 EDT
(In reply to Steve Northover from comment #13)
> In particular, something like this in an HTML file:
> 
> <script src="javascript/counter.js"></script>
> <script src="javascript/board.js"></script>
> <script src="javascript/main.js"></script>
> 
> Why would the files already be seen by Tern?

In my example I'm inlining the contents of counter.js into index.html when open declaration is called.  I have different contents in index.html than what is saved in the various caches (when eslint validation was run, etc.).
Comment 15 Michael Rennie CLA 2015-08-24 14:23:08 EDT
(In reply to Steve Northover from comment #13)
> In particular, something like this in an HTML file:
> 
> <script src="javascript/counter.js"></script>
> <script src="javascript/board.js"></script>
> <script src="javascript/main.js"></script>
> 
> Why would the files already be seen by Tern?

When you invoke any of the commands in your HTML, those files are resolved and fed to Tern (building them in automatically as the dependency graph).

The problem Curtis is referring to - about scopes - is that depending on how any of those scripts actually exports stuff the inferred results differ.

1. main.js defines a function declaration main.

function main() {}

main is leaked into the global scope (not explicitly set), so Tern treats it as a 'maybe this is wanted' and seems to be adding it to a sub-scope (not the official global scope)

2. main.js changed to assignment expression

this.main = function() {}

main is explicitly set in the global scope, and is inferred as such, and is easily found / used by open decl, etc.

So there are a few things I can do here (once the html dep code is in git), I can force Tern to always add all unknowns to the global scope (could cause false positives in requests), or make sure to properly expose the 'maybe' scope as a fully resolved / propagated type scope rather than just the 'maybeProps' mention there is now.


Curtis, can you open a new bug for the scope problem once you put some code in master that I can test with?
Comment 16 Curtis Windatt CLA 2015-08-25 18:03:14 EDT
So I was able to track down the cause of the scoping problem.  The Tern node plug-in was changing the scope the types were added to (I didn't realize that the 'exports' scope was actually a Node plug-in thing).  Disabling the node plug-in and everything works great.

I also have a workaround/fix for Tern not allowing me to reparent a known file.

Meanwhile Mike created a Tern plug-in that does the same operations inside the Tern worker and it appears to be mostly working.  We will work on it tomorrow some more to see what is working and what isn't.  We plan to release the code to master, possibly with the plug-in disabled depending on how our testing goes.
Comment 17 Michael Rennie CLA 2015-08-26 11:43:25 EDT
(In reply to Curtis Windatt from comment #16)

> Meanwhile Mike created a Tern plug-in that does the same operations inside
> the Tern worker and it appears to be mostly working.  We will work on it
> tomorrow some more to see what is working and what isn't.  We plan to
> release the code to master, possibly with the plug-in disabled depending on
> how our testing goes.

I pushed the plugin to master. It allows Tern to directly work on an HTML file.

I think the fix for bug 473964 will fix the nodejs plugin scoping issues, as it will add support to 'know' if the plugin should even be used in a given context.

The git link: http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=e8d5ee745bad5a419e20dba2dfeaddc0c632e11d
Comment 18 Michael Rennie CLA 2015-08-26 16:44:06 EDT
Pushed in support for all of the commands to directly pas the HTML to Tern:

http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=feea42ebec37bc63cecad36f297caadcb954aca4
Comment 19 Curtis Windatt CLA 2015-08-26 17:42:30 EDT
This is working great!

My current list of issues:
1) When adding a file the Tern does not add the parent to any known files.
This doesn't seem to cause any problems opening declaration in the added files so this may not be a bug at all.  Considering filing an issue against Tern to investigate further.

2) Test failures due to missing exports and module assist proposals
I think that the new behaviour is more correct and better for the user, so I have fixed the tests:
http://git.eclipse.org/c/orion/org.eclipse.orion.client.git/commit/?id=ff37afe6548ecaa9d34ce5666959fc0dbe95c532

3) Find script blocks doesn't match the spec
Bug 475962

4) Types in the top level scope are available everywhere
Bug 475964
This causes 6 test failures

5) Can't use tooling on onclick and other function attributes
Bug 475965

We can follow up on these issues in their respective bugs.  Reassigning to Mike as the HTML plug-in portion a more difficult piece than the dependency collection.  Closing as FIXED.
Comment 20 Steve Northover CLA 2015-08-27 10:04:31 EDT
Can you tell me what is supposed to be working?  For example, in the minesweeper-object project, I try to navigate from main.js to counter.js using setValue() and it fails.  Should it work?  The code in minesweeper-objects is some of the simplest possible OO JavaScript around.

I can open a bug report.
Comment 21 Michael Rennie CLA 2015-08-27 10:20:30 EDT
(In reply to Steve Northover from comment #20)
> Can you tell me what is supposed to be working?  For example, in the
> minesweeper-object project, I try to navigate from main.js to counter.js
> using setValue() and it fails.  Should it work?  The code in
> minesweeper-objects is some of the simplest possible OO JavaScript around.
> 
> I can open a bug report.

That should be working as all of the minesweeper* stuff is dumped into the global scope. Please open a bug.

The HTML -> JS case is working 100%: i.e. navigate / use assist / etc while working in a script block.
Comment 22 Steve Northover CLA 2015-08-27 10:57:45 EDT
Right but being in one JS file and navigating to another should work.  Anyhow, I will enter the bug.
Comment 23 Steve Northover CLA 2015-08-27 11:00:07 EDT
I am a lying sack of ... 

Must be that I was not running the latest build.  It's working like a charm!
Comment 24 Curtis Windatt CLA 2015-08-27 11:40:03 EDT
I said I would change the assignee but never actually applied the change...

(In reply to Steve Northover from comment #23)
> I am a lying sack of ... 
> 
> Must be that I was not running the latest build.  It's working like a charm!

The behaviour currently depends on what files are in the Tern context.  Everything that Tern sees in the global scope is getting added to assist proposals for all files.  So if you edit all the script/html files you will get proposals for all of their types.  If you have only visited the one script file, there is no way for Tern to know that some other script file contributes something to the global scope that we care about.

We need to limit the proposals to just the file and its dependents (Bug 4759654). Once that is fixed, then your case (script to unrelated script) won't work at all.

I opened Bug 476062 to discuss how to tell Tern a set of scripts are related.
Comment 25 Steve Northover CLA 2015-08-27 12:03:11 EDT
Ok, this is pretty bad in the sense that you think something is working and it is, then it isn't etc.  Will go over to the other bug.