Skip to content

Commit

Permalink
Better content assist support for node.js.
Browse files Browse the repository at this point in the history
We detect node.js files as those with the following jslint directive:

  /*jslint node:true */

For such files, content assist will now suggest appropriate globals.
Furthermore, if a built-in node.js module is included via a require()
call, content assist can make appropriate suggestions for the variable
holding the return value of the call.  The index file nodeIndex.js
is still incomplete and a work in progress.

Also includes related cleanup and improvement to various parts of the
content assist code.  Finally, add indexFileParsingTests.(html/js), with
separate regression tests for our code for parsing index files.

Signed-off-by: Manu Sridharan <msridhar@us.ibm.com>
  • Loading branch information
msridhar committed Sep 23, 2013
1 parent 3c65cd0 commit c067144
Show file tree
Hide file tree
Showing 10 changed files with 2,300 additions and 326 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2320,10 +2320,10 @@ define([
tests["test node1"] = function() {
var results = computeContentAssist(
"/*jslint node:true*/\n" +
"mod", "mod"
"glo", "glo"
);
return testProposals(results, [
["module", "module : Global"]
["global", "global : Global"]
]);
};

Expand All @@ -2340,17 +2340,17 @@ define([
tests["test node3"] = function() {
var results = computeContentAssist(
"/*jslint browser:false node:true*/\n" +
"mod", "mod"
"glo", "glo"
);
return testProposals(results, [
["module", "module : Global"]
["global", "global : Global"]
]);
};

tests["test node4"] = function() {
var results = computeContentAssist(
"/*jslint node:false*/\n" +
"mod", "mod"
"glo", "glo"
);
return testProposals(results, []);
};
Expand All @@ -2372,7 +2372,7 @@ define([
tests["test node6"] = function() {
var results = computeContentAssist(
"/*jslint node: xxx true*/\n" +
"mod", "mod"
"glo", "glo"
);
return testProposals(results, []);
};
Expand All @@ -2381,26 +2381,26 @@ define([
tests["test node7"] = function() {
var results = computeContentAssist(
"/*jslint node xxxx : true*/\n" +
"mod", "mod"
"glo", "glo"
);
return testProposals(results, []);
};

// configuration from .scripted
tests["test node8"] = function() {
var results = computeContentAssist(
"mod", "mod", null, {options:{node:true}}
"glo", "glo", null, {options:{node:true}}
);
return testProposals(results, [
["module", "module : Global"]
["global", "global : Global"]
]);
};

// configuration from .scripted is overridden by in file comments
tests["test node9"] = function() {
var results = computeContentAssist(
"/*jslint node:false*/\n" +
"mod", "mod", null, {options:{node:true}}
"glo", "glo", null, {options:{node:true}}
);
return testProposals(results, []);
};
Expand All @@ -2409,10 +2409,10 @@ define([
tests["test node10"] = function() {
var results = computeContentAssist(
"/*jslint node:true*/\n" +
"mod", "mod", null, {options:{browser:true}}
"glo", "glo", null, {options:{browser:true}}
);
return testProposals(results, [
["module", "module : Global"]
["global", "global : Global"]
]);
};

Expand All @@ -2427,6 +2427,37 @@ define([
]);
};

tests["test node12"] = function() {
var results = computeContentAssist(
"/*jslint node:true*/\n" +
"process.", ""
);
// just testing that we don't crash
return results.then(function () {});
};

tests["test node13"] = function() {
var results = computeContentAssist(
"/*jslint node:true*/\n" +
"var x = require(\"fs\");\n" +
"x.o", "o"
);
return testProposals(results, [
["open(path, flags, mode, callback)", "open(path, flags, mode, callback) : undefined"],
["openSync(path, flags, [mode])", "openSync(path, flags, [mode]) : Number"]
]);
};

tests["test node14"] = function() {
var results = computeContentAssist(
"/*jslint node:true*/\n" +
"process.stdout.wr", "wr"
);
return testProposals(results, [
["write(chunk, [encoding], [callback])", "write(chunk, [encoding], [callback]) : Boolean"]
]);
};


////////////////////////////////////////
// jsdoc tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<script src="../../orion/plugin.js"></script>
<script src="../../requirejs/require.js"></script>
<script>
/*global window require */
require({
baseUrl: '../..',
paths: {
"scriptedLogger": "plugins/esprima/scriptedLogger",
text: 'requirejs/text',
i18n: 'requirejs/i18n',
domReady: 'requirejs/domReady'
}
});
window.onload = function() {
require(["orion/test","js-tests/esprima/indexFileParsingTests"],
function(test, jsTests) {
test.run(jsTests);
});
};
</script>
</head>
<body>
<h1>Unit tests for index file parsing</h1>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
/*******************************************************************************
* @license
* Copyright (c) 2012 VMware, Inc. All Rights Reserved.
* Copyright (c) 2013 IBM Corporation.
*
* THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
* ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
* CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
* You can obtain a current copy of the Eclipse Public License from
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* Contributors:
* Andrew Eisenberg (VMware) - initial API and implementation
* Manu Sridharan (IBM) - Various improvements
******************************************************************************/

/*global define esprima console setTimeout doctrine*/
define(["plugins/esprima/typesFromIndexFile", "plugins/esprima/typeEnvironment", "orion/assert"], function(mTypes, typeEnv, assert) {

//////////////////////////////////////////////////////////
// helpers
//////////////////////////////////////////////////////////

function testSig(ternSig, closureSig, constructorName) {
assert.equal(mTypes.ternSig2ClosureSig(ternSig, constructorName), closureSig, "Bad conversion");
}

function testType(type, name, expectedTypeInfo) {
var result = mTypes.parseType(type, name);
assert.equal(JSON.stringify(result.typeInfo), JSON.stringify(expectedTypeInfo), "Bad parse");
}

function makeEnvironmentOptionsFromIndex(indexDataArr) {
var options = {};
options.buffer = "";
options.uid = "0";
options.indexData = indexDataArr;
return options;
}

function checkEnvironment(indexData, cb) {
var options = makeEnvironmentOptionsFromIndex([indexData]);
var envPromise = typeEnv.createEnvironment(options);
var result = envPromise.then(cb);
return result;
}

//////////////////////////////////////////////////////////
// tests
//////////////////////////////////////////////////////////

var tests = {};

tests["test basic 1"] = function() {
testSig("fn() -> String", "function():String");
};

tests["test basic 2"] = function() {
testSig("fn(m: Number, n?: Number) -> Boolean", "function(m:Number,n:Number=):Boolean");
};

tests["test constructor 1"] = function() {
// TODO is this really right? comma after Fizz?
testSig("fn()", "function(new:Fizz):Fizz", "Fizz");
};

tests["test array of functions"] = function() {
testSig("fn() -> [fn()]", "function():Array");
};
tests["test callback"] = function() {
testSig("fn(cb: fn(x: Object) -> Object) -> Number", "function(cb:function(x:Object):Object):Number");
};

tests["test callback 2"] = function() {
testSig("fn(cb: fn(x: Object) -> Object) -> fn(y: Object) -> Object",
"function(cb:function(x:Object):Object):function(y:Object):Object");
};

tests["test callback 3"] = function() {
testSig("fn(cb: fn(x: Object) -> fn(z: Object) -> Object, cb2: fn(p: Object) -> String) -> fn(y: Object) -> Object",
"function(cb:function(x:Object):function(z:Object):Object,cb2:function(p:Object):String):function(y:Object):Object");
};

tests["test type 1"] = function() {
var type = {
fizz: "String",
bazz: "Number"
};
var expected = {
"Foo": {
"fizz": {
"_typeObj": {
"type": "NameExpression",
"name": "String"
}
},
"bazz": {
"_typeObj": {
"type": "NameExpression",
"name": "Number"
}
},
"$$isBuiltin": true
}
};
testType(type, "Foo", expected);
};

tests["test type reference with dot"] = function() {
var type = {
foo: "+x.OtherType"
};
var expected = {
"Foo": {
"foo": {
"_typeObj": {
"type": "NameExpression",
"name": "x..OtherType..prototype"
}
},
"$$isBuiltin": true
}
};
testType(type, "Foo", expected);
};

tests["test environment basic"] = function() {
var index = {
bizz: "String"
};
return checkEnvironment(index, function (env) {
assert.equal("String", env.lookupTypeObj("bizz").name, "bad environment");
});
};

tests["test environment prototype"] = function() {
var index = {
Fizz: {
"!type": "fn(p:String)",
prototype: {
x: "String"
}
},
Buzz: {
"!type": "fn(p:String)",
prototype: {
"!proto": "Fizz.prototype",
y: "String"
}
}
};
return checkEnvironment(index, function (env) {
var t = env.lookupTypeObj("x", "Fizz..prototype");
// TODO figureout out what to check here!!!
});
};

return tests;
});
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ define(["plugins/esprima/esprimaVisitor", "plugins/esprima/typeEnvironment", "pl
}

function createInferredProposals(targetTypeName, env, completionKind, prefix, replaceStart, proposals, relevance) {
var prop, propTypeObj, propName, res, type = env.getAllTypes()[targetTypeName], proto = type.$$proto;
var prop, propTypeObj, propName, res, type = env.lookupQualifiedType(targetTypeName), proto = type.$$proto;
if (!relevance) {
relevance = 100;
}
Expand Down Expand Up @@ -265,6 +265,8 @@ define(["plugins/esprima/esprimaVisitor", "plugins/esprima/typeEnvironment", "pl
}
if (proposalUtils.looselyMatches(prefix, propName)) {
propTypeObj = type[prop].typeObj;
// if propTypeObj is a reference to a function type,
// extract the actual function type
if ((env._allTypes[propTypeObj.name]) && (env._allTypes[propTypeObj.name].$$fntype)) {
propTypeObj = env._allTypes[propTypeObj.name].$$fntype;
}
Expand Down

0 comments on commit c067144

Please sign in to comment.