Jump to: navigation, search

Orion/Dependency resolution

Dependency resolution refers to the ability to resolve a type of cross-file dependency to a file in the workspace at development time. Examples of dependencies within our scope are:

  • HTML files: src and href attributes
  • CSS files: @import statements and url( .. )
  • JS files: define([ deps.. ]) and require([ deps.. ])AMD modules
  • JS files: require( "dep/path" )Node.js/CommonJS
  • JS files importScripts( urls.. )web worker API
    • Note that importScripts' arguments are resolved relative to the calling script's location, which is not necessarily the same as window.location.

Dependency resolution is a prerequisite feature to cross-file type inference, content assist, refactoring and open-type like navigation.

Minimally Useful Cases

  • Allow user to ctrl+click a CSS @import to open the imported file in an editor tab, if it is within the workspace.
  • Allow user to ctrl+click an AMD define entry to open / find the file

Concepts

  • Dependency: a reference to some logical path (LP).
  • Logical path (LP): whatever goes inside the src="___", @import "___", require(___), etc.
    • The LP is opaque to everything but a Resolver.
    • Example: in JS, depending on the context, an LP may be either a commonJS module path (Node.js), a path in the local file system (Node.js), a web path (browser/worker), or an AMD module ID.
  • Resolver: maps LP to a workspace path (WP).
    • And vice-versa? Maybe.
    • WPs can be fetched/parsed using the usual Orion FileClient API. Thus they are tractable to the tooling, assuming the necessary APIs are exposed.
    • Compare to IScriptResolver[1] from JDT.
  • Web Path Config (WPC): captures the path-translation info necessary to map from an LP that is a web location.
    • The notion of WPC is important because a resource's location on a web server is generally not the same as its location in the workspace. For example, a file located at a repo path of /src/webapp/static/js/foo.js may be exposed on the web as /admin/js/foo.js. Dependencies will refer to the latter, not the former.
    • The user must assist us in constructing the WPC. See how ReSharper[2] does it.
      • A slightly different take: if the development path were encoded into the file itself (perhaps via a GIT hook?) then the WPC can be constructed at the far end (after it's been staged on the server) by iterating over the deployed structure and reading the dev path from the file itself.
      • MM: ^ This is interesting. It reminds me of JS source maps. But it would require the tooling to be fully aware of the build process, correct?
      • Note that the responsibility of generating / maintaining the WPC should be placed on the person responsible for defining the shape of the deployed code, not on users; only they are in a position to know when the shape changes... The WPC only needs to be updated when this shape changes, incremental would be nice for simple file additions...
    • The WPC is of interest to any Resolvers that may encounter web paths as LPs.
    • A WPC is a subset of the site structure defined by an Orion site configuration. (It's basically a site configuration that does not support REST API path mappings.) Should factor out any commonality here.
    • WPC should live at the project level, possibly inside project.json.
    • Could also include in-file directives similar to TypeScript ///<reference path="to/declaration.d.ts"/>

Questions (TODO)

  • What is the basic interface of Resolver?
    • toWorkspacePath(LP) → WP
    • (?) toLogicalPath(WP) → LP
  • What implementations of Resolver do we need?
    • GenericWebResolver, CommonJSResolver, AMDResolver extends GenericWebResolver...
    • Which Resolvers leverage the WPC?
  • What are the exact semantics/shape of a WPC?
    • In complex WPC's like Orion's, the map of LP:WP is likely 1:N. For example consider if both org.eclipse.orion.client.ui and org.eclipse.orion.client.core have a file named plugin.js. An AMD dep on "orion/plugin" could resolve to either file. How to resolve ambiguity? Rank? Show an error?
    • EM: presumably during the 'deploy' these files end up in different directories so I'm unsure where the ambiguity creeps in
      • MM: Suppose the tooling has no connection to the 'deployed' code running on an actual server somewhere. Then you need rules for mapping paths using only information in the workspace. If you give users expressive structures for creating those rules, it usually permits ambiguity.
        • For example, a regex-like rule would capture most of Orion's web project structure: map workspace path bundles/[A-Za-z.]+/web/(.*) to web path /$1.
        • For projects with less crazy project structure than Orion's, this is probably a non-issue.
  • Do we expect a stanza present in JS files to distinguish whether Node.js resolution logic or AMD should be used? (eg. /*eslint-env amd*/ versus /*eslint-env node*/).
  • Should we expose a user action to select the root context (base HTML file, base JS script, etc) -- giving the base URL they're working against on the web.

References

  1. http://git.eclipse.org/c/jsdt/webtools.jsdt.git/tree/bundles/org.eclipse.wst.jsdt.debug.core/src/org/eclipse/wst/jsdt/debug/internal/core/model/ScriptResolverExtension.java
  2. http://blog.jetbrains.com/dotnet/2013/04/15/resharpers-web-path-mapping-explained/