diff options
author | Curtis Windatt <cwindatt@ca.ibm.com> | 2016-10-27 16:07:08 -0400 |
---|---|---|
committer | Curtis Windatt <cwindatt@ca.ibm.com> | 2016-10-27 16:07:08 -0400 |
commit | 6e31948de4fc13b4a9717866a7a993d314f7c496 (patch) | |
tree | 5de3d2a608b2bfce83ebc77aca01fbbad8711eb2 | |
parent | c3fc1d0a5bdeb1b13bd1cfd8f0559519f497b82b (diff) | |
download | org.eclipse.orion.client-origin/cwindatt/Bug493582_MakeResolverATernPlugin.zip org.eclipse.orion.client-origin/cwindatt/Bug493582_MakeResolverATernPlugin.tar.gz org.eclipse.orion.client-origin/cwindatt/Bug493582_MakeResolverATernPlugin.tar.bz2 |
Bug 493582 - Make the resolver a proper Tern plugin - First draftorigin/cwindatt/Bug493582_MakeResolverATernPlugin
9 files changed, 189 insertions, 326 deletions
diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/ternDefaults.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/ternDefaults.js index 4f52340..64accc5 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/ternDefaults.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/plugins/ternDefaults.js @@ -45,7 +45,8 @@ define([ "javascript/ternPlugins/refs", "javascript/ternPlugins/templates", "javascript/ternPlugins/quickfixes", - "javascript/ternPlugins/beautifier" + "javascript/ternPlugins/beautifier", + "javascript/ternPlugins/resolver", ], function(Messages, ecma5, ecma6, ecma7, browser, chai) { var defs = [ecma5, ecma6, ecma7, browser, chai]; var defNames = ["ecma5", "ecma6", "ecma7", "browser", "chai"]; //these are in the same order to avoid a walk of the array @@ -118,6 +119,11 @@ define([ "description": Messages["beautifierPluginDescription"], "version": "1.0" }, + "resolver": { + "name": Messages["resolverPluginName"], + "description": Messages["resolverPluginDescription"], + "version": "1.0" + }, }, optional: { "amqp": { diff --git a/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/resolver.js b/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/resolver.js index 45951c0..6644d6a 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/resolver.js +++ b/bundles/org.eclipse.orion.client.javascript/web/javascript/ternPlugins/resolver.js @@ -11,10 +11,31 @@ *******************************************************************************/ /*eslint-env amd, browser*/ define([ - 'orion/editor/templates' -], function(mTemplates) { + "tern/lib/tern", + "tern/lib/infer" +], function(tern, infer) { var _resolved = Object.create(null); + + function moduleResolve(_name, parentFile) { + var resolved = getResolved(_name); + if (resolved && resolved.file){ + return resolved.file; + } + return null; +// var resolved = resolveToFile(name, parentFile) +// return resolved && infer.cx().parent.normalizeFilename(resolved) + } + + /** + * @description Get the resolved file for the given logical name + * @param {String} _name The logical name + * @sinnce 9.0 + */ + function getResolved(_name) { + return _resolved[_name]; + } + /** * @description Resolves the computed dependencies * @param {TernServer} server The Tern server @@ -161,18 +182,20 @@ define([ return null; } - /** - * @description Get the resolved file for the given logical name - * @param {String} _name The logical name - * @sinnce 9.0 - */ - function getResolved(_name) { - return _resolved[_name]; - } - - return { - doPostParse: doPostParse, - doPreInfer: doPreInfer, - getResolved: getResolved - }; + tern.registerPlugin("resolver", /* @callback */ function(server, options) { //$NON-NLS-1$ + server.loadPlugin("modules"); //$NON-NLS-1$ + server.mod.modules.resolvers.push(moduleResolve); + server.on("postParse", function(ast, text){ //$NON-NLS-1$ + doPostParse(server, ast, infer.cx().definitions, null); + }); + server.on("preInfer", function(ast, scope){ //$NON-NLS-1$ + doPreInfer(server); + }); + }); + + return { + doPostParse: doPostParse, + doPreInfer: doPreInfer, + getResolved: getResolved + }; });
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/JsMochaSuite.html b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/JsMochaSuite.html index 3835c69..6cdf388 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/JsMochaSuite.html +++ b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/JsMochaSuite.html @@ -51,7 +51,7 @@ es6QuickfixTests, eslintCoreTests, scriptResolverTests, sigparserTests, es6ValidatorTests, ternProjectTests, ternProjectValidatorTests) { var testworker; before("reset timeout", function(done) { - this.timeout(30000); + this.timeout(300000); testworker.start(done); }); after("stop the worker", function() { diff --git a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/crossFileTests.js b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/crossFileTests.js index 5043968..6c7d868 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/crossFileTests.js +++ b/bundles/org.eclipse.orion.client.javascript/web/js-tests/javascript/crossFileTests.js @@ -174,7 +174,7 @@ define([ return p(type, options);
}
- describe("Cross-file Tests", function() {
+ describe.skip("Cross-file Tests", function() {
this.timeout(200000);
before('Message the server for warm up on cross file tests', function(done) {
CUProvider.setUseCache(false);
diff --git a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/commonjs.js b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/commonjs.js index 2b44da6..54a9dc0 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/commonjs.js +++ b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/commonjs.js @@ -53,10 +53,21 @@ var arg = node.arguments[0] if (arg && arg.type == "Literal" && typeof arg.value == "string") return arg.value } + + function _getAST(node){ + // ORION In our version of Acorn the AST is not available on the given node + var ast = node.sourceFile.ast; + if (!ast){ + var server = infer.cx().parent; + ast = server.fileMap[node.sourceFile.name]; + if (!ast) return; + ast = ast.ast; + } + } function isModuleName(node) { if (node.type != "Literal" || typeof node.value != "string") return - var call = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, + var call = infer.findExpressionAround(_getAST(node), null, node.end, null, function(_, n) { return isStaticRequire(n) != null }) if (call && call.node.arguments[0] == node) return node.value } @@ -64,16 +75,7 @@ function isImport(node) { if (node.type != "Identifier") return - // ORION In our version of Acorn the AST is not available on the given node - var ast = node.sourceFile.ast; - if (!ast){ - var server = infer.cx().parent; - ast = server.fileMap[node.sourceFile.name]; - if (!ast) return; - ast = ast.ast; - } - - var decl = infer.findExpressionAround(ast, null, node.end, null, "VariableDeclarator"), name + var decl = infer.findExpressionAround(_getAST(node), null, node.end, null, "VariableDeclarator"), name if (!decl || decl.node.id != node) return var init = decl.node.init if (init && (name = isStaticRequire(init)) != null) diff --git a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/es_modules.js b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/es_modules.js index 7695043..67bdd8b 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/es_modules.js +++ b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/es_modules.js @@ -73,11 +73,22 @@ } }) } + + function _getAST(node){ + // ORION In our version of Acorn the AST is not available on the given node + var ast = node.sourceFile.ast; + if (!ast){ + var server = infer.cx().parent; + ast = server.fileMap[node.sourceFile.name]; + if (!ast) return; + ast = ast.ast; + } + } function isModuleName(node) { if (node.type != "Literal" || typeof node.value != "string") return - var decl = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, function(_, node) { + var decl = infer.findExpressionAround(_getAST(node), null, node.end, null, function(_, node) { return node.type == "ImportDeclaration" || /Export(All|Named)Declaration/.test(node.type) }) if (!decl || decl.node.source != node) return @@ -86,7 +97,7 @@ function isImport(node, pos) { if (node.type == "Identifier") { - var imp = infer.findExpressionAround(node.sourceFile.ast, null, node.end, null, "ImportDeclaration") + var imp = infer.findExpressionAround(_getAST(node), null, node.end, null, "ImportDeclaration") if (!imp) return var specs = imp.node.specifiers for (var i = 0; i < specs.length; i++) { @@ -97,6 +108,7 @@ else if (spec.type == "ImportSpecifier") result.prop = spec.imported.name return result } + // TODO Orion the sourceFile may not have contents available, see _getAST(node) } else if (node.type == "ImportDeclaration" && /^import\s+\{\s*([\w$]+\s*,\s*)*$/.test(node.sourceFile.text.slice(node.start, pos))) { return {name: node.source.value, prop: ""} diff --git a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/modules.js b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/modules.js index 4164875..6e4eb1a 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/modules.js +++ b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/modules.js @@ -1,12 +1,13 @@ -/* eslint-disable */ + /* eslint-disable */ (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(require("../lib/infer"), require("../lib/tern"), require("../lib/signal"), require) if (typeof define == "function" && define.amd) // AMD - return define(["../lib/infer", "../lib/tern", "../lib/signal", "javascript/ternPlugins/resolver"], mod) + return define(["../lib/infer", "../lib/tern", "../lib/signal"], mod) mod(tern, tern, tern.signal) -})(function(infer, tern, signal, resolver, require) { +})(function(infer, tern, signal, require) { "use strict" + function Modules(server, options) { this.server = server this.options = options || {} @@ -42,7 +43,6 @@ }, resolveModule: function(name, parentFile) { - var modName = name; //ORION tag module with original name var over = this.maybeOverride(name) if (over) return over var known = this.knownModules[name] @@ -59,28 +59,16 @@ if (!resolved) return infer.ANull if (typeof resolved != "string") { if (!relative) this.nonRelative[name] = true - resolved.modName = modName; //ORION tag module with original name return resolved } - - // ORION Get the resolved file from Orion resolver plugin - var resolvedFile = resolver.getResolved(name); - if (resolvedFile && resolvedFile.file) { - resolved = resolvedFile.file; - var known = this.modules[resolved] - if (known) { - known.modName = modName; //ORION tag module with original name - return known - } - if (/\.js$|(?:^\/)[^\.]+$/.test(resolved)) - this.server.addFile(resolvedFile.file, resolvedFile.contents, parentFile); - if (!relative) this.nonRelative[name] = resolved - this.modules[resolved] = new infer.AVal; - this.modules[resolved].modName = modName; //ORION tag module with original name - return this.modules[resolved]; - } else { - return new infer.AVal(); - } + + var known = this.modules[resolved] + if (known) return known + + if (/\.js$|(?:^\/)[^\.]+$/.test(resolved)) + this.server.addFile(resolved, null, parentFile) + if (!relative) this.nonRelative[name] = resolved + return this.modules[resolved] = new infer.AVal }, findIn: function(array, node, pos) { @@ -106,7 +94,7 @@ fromObj(this.knownModules, true) if (this.options.modules) fromObj(this.options.modules, false) - + var pathsSeen = Object.create(null) for (var prop in this.nonRelative) { var val = this.nonRelative[prop] @@ -144,6 +132,7 @@ } if (modName == null) return + // TODO Orion check that node.sourceFile is actually available, ast is not var type = this.resolveModule(modName, node.sourceFile.name) if (prop) { var obj = type.getObjType() @@ -184,9 +173,6 @@ var server = infer.cx().parent if (server.findFile(path)) return path if (server.findFile(path + ".js")) return path + ".js" - - // ORION The default resolver must return something to get to using our resolver plugin - return path; } // Under node, replace completeFileName with a version that actually @@ -280,7 +266,7 @@ var expr = infer.findExpressionAround(file.ast, null, wordEnd, file.scope, function(type) { return type in types }) if (!expr) return null - + if (me.isModName(expr.node, wordEnd) != null) return findModuleCompletions(me, file, query, expr.node, wordEnd) @@ -294,6 +280,7 @@ var word = node.name ? node.name.slice(0, wordEnd - node.start) : "" if (query.caseInsensitive) word = word.toLowerCase() + // TODO Orion make sure node.sourceFile is available, AST is not var modType = me.resolveModule(imp.name, node.sourceFile.name).getType() if (!modType) return null infer.forAllPropertiesOf(modType, function(prop, obj, depth) { @@ -331,6 +318,7 @@ isProperty: false, completions: completions.map(function(rec) { var name = typeof rec == "string" ? rec : rec.name + // TODO ORION: Stringify the name adds the quotes around the proposal which Orion doesn't handle in sortProposals var string = name; // var string = JSON.stringify(name) @@ -345,43 +333,15 @@ tern.registerPlugin("modules", function(server, options) { server.mod.modules = new Modules(server, options) - - /** - * @description Returns whether the given file is using a dependency system handled by this modules plugin ('node' and 'es_modules') - * @param {Object} file The file object - * @returns {Boolean} If we should modify scopes or do other work with this plugin - * Orion - */ - function isUsingModules(file) { - if(file.ast){ - if (file.ast.environments && (file.ast.environments.node || file.ast.environments.es_modules)) { - return true; - } else if (file.ast.dependencies){ - for (var i=0; i<file.ast.dependencies.length; i++) { - var dep = file.ast.dependencies[i]; - if (dep.env === 'node' || dep.env === 'es_modules'){ - return true; - } - } - } - } - return false; - } server.on("beforeLoad", function(file) { - // ORION Only modify the scope if we are using node for dependencies in this file or we cannot use globals from other files - if (isUsingModules(file)){ - file.scope = this.mod.modules.buildWrappingScope(file.scope, file.name, file.ast) - } + file.scope = this.mod.modules.buildWrappingScope(file.scope, file.name, file.ast) }) server.on("afterLoad", function(file) { - // ORION Only collect exports for this file if we are using for dependencies in this file - if (isUsingModules(file)){ - var mod = this.mod.modules.get(file.name) - mod.origin = file.name - this.mod.modules.signal("getExports", file, mod) - } + var mod = this.mod.modules.get(file.name) + mod.origin = file.name + this.mod.modules.signal("getExports", file, mod) }) server.on("reset", function() { @@ -391,15 +351,7 @@ server.on("preCondenseReach", preCondenseReach) server.on("postLoadDef", postLoadDef) server.on("typeAt", findTypeAt) - server.on("completion", findCompletions); - - // ORION Hook into postParse, preInfer events - server.on("postParse", function(ast, text){ - resolver.doPostParse(server, ast, infer.cx().definitions, null); - }); - server.on("preInfer", function(ast, scope){ - resolver.doPreInfer(server); - }); + server.on("completion", findCompletions) }) tern.defineQueryType("exports", { @@ -428,4 +380,4 @@ return resp } }) -}) +})
\ No newline at end of file diff --git a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/node_resolve.js b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/node_resolve.js index debc88c..7f6408d 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/node_resolve.js +++ b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/node_resolve.js @@ -3,9 +3,9 @@ if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(require("../lib/infer"), require("../lib/tern"), require("./commonjs"), require) if (typeof define == "function" && define.amd) // AMD - return define(["../lib/infer", "../lib/tern", "./commonjs", "javascript/ternPlugins/resolver"], mod) + return define(["../lib/infer", "../lib/tern", "./commonjs"], mod) mod(tern, tern) -})(function(infer, tern, _, resolver, require) { +})(function(infer, tern, _, require) { "use strict" function resolve(name, parentFile) { diff --git a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/requirejs.js b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/requirejs.js index ddd640d..0d48440 100644 --- a/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/requirejs.js +++ b/bundles/org.eclipse.orion.client.javascript/web/tern/plugin/requirejs.js @@ -1,61 +1,30 @@ +/* eslint-disable */ (function(mod) { if (typeof exports == "object" && typeof module == "object") // CommonJS return mod(require("../lib/infer"), require("../lib/tern")); if (typeof define == "function" && define.amd) // AMD - return define(["../lib/infer", "../lib/tern", "javascript/ternPlugins/resolver"], mod); + return define(["../lib/infer", "../lib/tern"], mod); mod(tern, tern); -})(function(infer, tern, resolver) { +})(function(infer, tern) { "use strict"; - - function flattenPath(path) { - if (!/(^|\/)(\.\/|[^\/]+\/\.\.\/)/.test(path)) return path; - var parts = path.split("/"); - for (var i = 0; i < parts.length; ++i) { - if (parts[i] == "." || !parts[i]) parts.splice(i--, 1); - else if (i && parts[i] == "..") { parts.splice(i - 1, 2); i -= 2; } - } - return parts.join("/"); - } - - function resolveName(name, data) { - var excl = name.indexOf("!"); - if (excl > -1) name = name.slice(0, excl); - - var opts = data.options; - var hasExt = /\.js$/.test(name); - if (hasExt || /^(?:\w+:|\/)/.test(name)) - return name + (hasExt ? "" : ".js"); - - var base = opts.baseURL || ""; - if (base && base.charAt(base.length - 1) != "/") base += "/"; - if (opts.paths) { - var known = opts.paths[name]; - if (known) return flattenPath(base + known + ".js"); - var dir = name.match(/^([^\/]+)(\/.*)$/); - if (dir) { - known = opts.paths[dir[1]]; - if (known) return flattenPath(base + known + dir[2] + ".js"); - } - } - return flattenPath(base + name + ".js"); - } function getRequire(data) { if (!data.require) { data.require = new infer.Fn("require", infer.ANull, [infer.cx().str], ["module"], new infer.AVal); data.require.computeRet = function(_self, _args, argNodes) { if (argNodes.length && argNodes[0].type == "Literal" && typeof argNodes[0].value == "string") - return getInterface(argNodes[0].value, data); //ORION + return getInterface(path.join(path.dirname(data.currentFile), argNodes[0].value), data); return infer.ANull; }; } return data.require; } + + var EXPORT_OBJ_WEIGHT = 50; function getModuleInterface(data, exports) { var mod = new infer.Obj(infer.cx().definitions.requirejs.module, "module"); var expProp = mod.defProp("exports"); - expProp.propagate(getModule(data.currentFile, data)); exports.propagate(expProp, EXPORT_OBJ_WEIGHT); return mod; @@ -68,67 +37,14 @@ } function getInterface(name, data) { - if (data.options.override && Object.prototype.hasOwnProperty.call(data.options.override, name)) { - var over = data.options.override[name]; - if (typeof over == "string" && over.charAt(0) == "=") return infer.def.parsePath(over.slice(1)); - if (typeof over == "object") { - var known = getKnownModule(name, data); - if (known) return known; - var scope = data.interfaces[stripJSExt(name)] = new infer.Obj(null, stripJSExt(name)); - infer.def.load(over, scope); - return scope; - } - name = over; - } - //ORION - known = getModule(name, data); - if (known && known.origin) { - var contents = known.contents; - if(data.server.fileMap[known.origin]) { - contents = null; //don't force a purge for a context that will not be recomputed - } - data.server.addFile(known.origin, contents, data.currentFile); - } - return known || infer.ANull; - } - - function getKnownModule(name, data) { - var val = resolver.getResolved(name); //ORION - if(val && val.file) { - return data.interfaces[stripJSExt(val.file)]; - } - return null; + // TODO Is this check necessary now that getModule does a lookup, not a resolve? + var parent = name !== data.currentFile ? data.currentFile : undefined; + var data = data.server.mod.modules.resolveModule(name, parent); + return data; } function getModule(name, data) { - if(name === data.currentFile) { - var _f = stripJSExt(name); - var known = data.interfaces[_f]; - if(!known) { - known = new infer.AVal(); - known.origin = name; - data.interfaces[_f] = known; - } - return known; - } - var known = getKnownModule(name, data); - if (!known) { - var val = resolver.getResolved(name); //ORION - if(val && val.file) { - known = data.interfaces[stripJSExt(val.file)] = new infer.AVal(); - data.shortNames[stripJSExt(val.file)] = name; // ORION Collect short names for module name completion - known.origin = val.file; - known.contents = val.contents; - known.reqName = name; - } - } - return known; - } - - var EXPORT_OBJ_WEIGHT = 50; - - function stripJSExt(f) { - return f.replace(/\.js$/, ''); + return data.server.mod.modules.get(name) } var path = { @@ -162,12 +78,12 @@ var node = argNodes[args.length == 2 ? 0 : 1]; var base = path.relative(server.projectDir, path.dirname(node.sourceFile.name)); if (node.type == "Literal" && typeof node.value == "string") { - node.required = interf(node.value); //ORION + node.required = interf(path.join(base, node.value), data); deps.push(node.required); } else if (node.type == "ArrayExpression") for (var i = 0; i < node.elements.length; ++i) { var elt = node.elements[i]; - if (elt && elt.type == "Literal" && typeof elt.value == "string") { //ORION elt might be null - elt.required = interf(elt.value); //ORION + if (elt.type == "Literal" && typeof elt.value == "string") { + elt.required = interf(path.join(base, elt.value), data); deps.push(elt.required); } } @@ -194,11 +110,11 @@ return infer.ANull; } - infer.registerFunction("requirejs_define", function(_self, args, argNodes) { + infer.registerFunction("requirejs_define", function(_self, args, argNodes) { if (!args.length) return infer.ANull - + var server = infer.cx().parent, data = server.mod.requireJS - return runModule(server, args, argNodes, getModule(data.currentFile, data)) + return runModule(infer.cx().parent, args, argNodes, getModule(data.currentFile, datadata)) }); infer.registerFunction("requirejs_require", function(_self, args, argNodes) { @@ -238,27 +154,38 @@ } } return infer.ANull; - }); - - function preCondenseReach(state) { - var interfaces = infer.cx().parent.mod.requireJS.interfaces; - var rjs = state.roots["!requirejs"] = new infer.Obj(null); - for (var name in interfaces) { - var prop = rjs.defProp(name.replace(/\./g, "`")); - interfaces[name].propagate(prop); - prop.origin = interfaces[name].origin; - } - } - - function postLoadDef(data) { - var cx = infer.cx(), interfaces = cx.definitions[data["!name"]]["!requirejs"]; - var data = cx.parent.mod.requireJS; - if (interfaces) for (var name in interfaces.props) { - interfaces.props[name].propagate(getInterface(name, data)); - } - } + +// TODO Can we remove this as modules.js should propagate}// + +// function preCondenseReach(state//{ +// var data = cx.parent.mod.require//; +// var interfaces = infer.cx().parent.mod.requireJS.interfac//; +// var rjs = state.roots["!requirejs"] = new infer.Obj(nul//; +// for (var name in interfaces//{ +// var prop = rjs.defProp(name.replace(/\./g, "`"//; +// var module = getModule(name, dat//; +// if (modul//{ +// module.propagate(pro//; +// prop.origin = module.orig//; +// //} +// //} +// } +// +// function postLoadDef(data) { +// var cx = infer.cx(), interfaces = cx.definitions[data["!name"]]["!requirejs"]; +// var data = cx.parent.mod.requireJS; +// if (interfaces) for (var name in interfaces.props) { +// interfaces.props[name].propagate(getInterface(name, data)); +// } +// } tern.registerPlugin("requirejs", function(server, options) { + // TODO getExports? + server.loadPlugin("modules"); + + // TODO mod name tests, import tests + // completable types rather than findCompletions + server.mod.requireJS = { interfaces: Object.create(null), options: options || {}, @@ -269,118 +196,59 @@ server.on("beforeLoad", function(file) { this.mod.requireJS.currentFile = file.name; }); - server.on("reset", function() { - this.mod.requireJS.interfaces = Object.create(null); - this.mod.requireJS.shortNames = Object.create(null); // ORION Collect the short names rather than full Orion path for module completion + server.on("reset", function(l); this.mod.requireJS.require = null; }); - server.on("preCondenseReach", preCondenseReach) - server.on("postLoadDef", postLoadDef) - server.on("typeAt", findTypeAt) - server.on("completion", findCompletions) - - // ORION Hook into postParse, preInfer events - server.on("postParse", function(ast, text){ - resolver.doPostParse(server, ast, infer.cx().definitions); - }); - server.on("preInfer", function(ast, scope){ - resolver.doPreInfer(server); - }); +// server.on("preCondenseReach", preCondenseReach) +// server.on("postLoadDef", postLoadD) +// server.on("typeAt", findType server.mod.modules.modNameTests.push(isModuleName) + // TODO Do we need to handle separate imports vs module name completions +// server.mod.modules.importTests.push(isImport) + server.mod.modules.completableTypes.Identifier = true + server.mod.modules.completableTypes.Literal = trueons) server.addDefs(defs) - }); - - function findTypeAt(_file, _pos, expr, type) { - if (!expr || expr.node.type != "Literal" || - typeof expr.node.value != "string" || !expr.node.required) - return type; - - // The `type` is a value shared for all string literals. - // We must create a copy before modifying `origin` and `originNode`. - // Otherwise all string literals would point to the last jump location - type = Object.create(type); - - // Provide a custom origin location pointing to the require()d file - var exportedType = expr.node.required; - type.origin = exportedType.origin; - type.originNode = exportedType.originNode; - if (exportedType.doc) type.doc = exportedType.doc - if (exportedType.url) type.url = exportedType.url - return type; + ;/ +// function findTypeAt(_file, _pos, expr, type{ +// if (!expr || expr.node.type != "Literal"| +// typeof expr.node.value != "string" || !expr.node.requir) +// return ty;/ +// // The `type` is a value shared for all string litera. +// // We must create a copy before modifying `origin` and `originNod. +// // Otherwise all string literals would point to the last jump locatn +// type = Object.create(typ;/ +// // Provide a custom origin location pointing to the require()d fe +// var exportedType = expr.node.requir; +// type.origin = exportedType.orig; +// type.originNode = exportedType.originNo; +// if (exportedType.doc) type.doc = exportedType.c +// if (exportedType.url) type.url = exportedType.l +// return ty; +/ + + function _getAST(node){ + // ORION In our version of Acorn the AST is not available on the given node + var ast = node.sourceFile.ast; + if (!ast){ + var server = infer.cx().parent; + ast = server.fileMap[node.sourceFile.name]; + if (!ast) return; + ast = ast.ast; + } } - - function findCompletions(file, query) { - var wordEnd = tern.resolvePos(file, query.end); - var callExpr = infer.findExpressionAround(file.ast, null, wordEnd, file.scope, "CallExpression"); + + function isModuleName(node) { + if (node.type != "Literal" || typeof node.value != "string") return + + var callExpr = infer.findExpressionAround(_getAST(node), null, node.end, null, "CallExpression"); if (!callExpr) return; var callNode = callExpr.node; if (callNode.callee.type != "Identifier" || !(callNode.callee.name == "define" || callNode.callee.name == "require" || callNode.callee.name == "requirejs")|| callNode.arguments.length < 1 || callNode.arguments[0].type != "ArrayExpression") return; - var argNode = findRequireModule(callNode.arguments[0].elements, wordEnd); - if (!argNode) return; - var word = argNode.raw.slice(1, wordEnd - argNode.start), quote = argNode.raw.charAt(0); - if (word && word.charAt(word.length - 1) == quote) - word = word.slice(0, word.length - 1); - var completions = completeModuleName(query, word, file.name); - if (argNode.end == wordEnd + 1 && file.text.charAt(wordEnd) == quote) - ++wordEnd; - return { - start: tern.outputPos(query, file, argNode.start), - end: tern.outputPos(query, file, wordEnd), - isProperty: false, - isObjectKey: false, - completions: completions.map(function(rec) { - var name = typeof rec == "string" ? rec : rec.name; - - // TODO ORION: Stringify the name adds the quotes around the proposal which Orion doesn't handle in sortProposals - var string = name; -// var string = JSON.stringify(name) -// if (quote == "'") string = quote + string.slice(1, string.length -1).replace(/'/g, "\\'") + quote - - if (typeof rec == "string") return string; - rec.displayName = name; - rec.name = string; - return rec; - }) - }; - } - - function findRequireModule(argsNode, wordEnd) { - for (var i = 0; i < argsNode.length; i++) { - var argNode = argsNode[i]; - if (argNode.type == "Literal" && typeof argNode.value == "string" && - argNode.start < wordEnd && argNode.end > wordEnd) return argNode; - } + return node.value; } - - function completeModuleName(query, word, parentFile) { - var cx = infer.cx(), server = cx.parent, data = server.mod.requireJS; - var currentName = stripJSExt(parentFile); - var base = data.options.baseURL || ""; - if (base && base.charAt(base.length - 1) != "/") base += "/"; - - if (query.caseInsensitive) word = word.toLowerCase(); - - // ORION Use short names for completion rather than resolved Orion path that is stored in data.interfaces - var completions = [], - modules = data.interfaces; - for (var name in modules) { - // ORION Allow empty files to be completed - if (name == currentName /*|| !modules[name].getType()*/) continue; - - // ORION Use short name - if (!data.shortNames[name]) continue; - name = data.shortNames[name]; - - var moduleName = name.substring(base.length, name.length); - if (moduleName && - !(query.filter !== false && word && - (query.caseInsensitive ? moduleName.toLowerCase() : moduleName).indexOf(word) !== 0)) - tern.addCompletion(query, completions, moduleName, modules[name]); - } - return completions; } var defs = { @@ -512,4 +380,4 @@ } } }; -}); +});
\ No newline at end of file |