test("QMLObjScope::gatherProperties()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var obj = new infer.Obj(null, "MyObject"); var scope = new plugin.QMLObjScope(fileScope, null, obj); // Define some properties fileScope.defProp("third", null); scope.defProp("first", null); scope.defProp("second", null); // Gather the properties and store them in the order they were received var props = []; scope.gatherProperties(function (prop, obj, depth) { props.push(prop); }); // Check the gathered properties for correctness (order matters) if (props.length !== 3) { return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")"); } if (props[0] !== "first") { return callback("fail", name, "- props[0] was not property 'first'"); } if (props[1] !== "second") { return callback("fail", name, "- props[1] was not property 'second'"); } if (props[2] !== "third") { return callback("fail", name, "- props[2] was not property 'third'"); } return callback("ok", name); }); });
test("QMLMemScope::gatherProperties() [Multiple Parent Scopes]", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var rootObj = new infer.Obj(null, "Root"); var rootObjScope = new plugin.QMLObjScope(fileScope, null, rootObj); var obj = new infer.Obj(null, "MyObject"); var objScope = new plugin.QMLObjScope(rootObjScope, null, obj); var scope = new plugin.QMLMemScope(objScope, null, fileScope); // Define a property on the Root Obj Type and Obj Type rootObj.defProp("notVisible", null); obj.defProp("visible", null); // Gather the properties and store them in the order they were received var props = []; scope.gatherProperties(function (prop, obj, depth) { props.push(prop); }); // Check the gathered properties for correctness (order matters) if (props.length !== 1) { return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")"); } if (props[0] !== "visible") { return callback("fail", name, "- props[0] was not property 'visible'"); } return callback("ok", name); }); });
test("QMLObjScope::defProp()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var obj = new infer.Obj(null, "MyObject"); var scope = new plugin.QMLObjScope(fileScope, null, obj); // Define some properties scope.defProp("first", null); scope.defProp("second", null); // Make sure there are no properties in the scopes themselves if (fileScope.props && fileScope.props.length > 0) { return callback("fail", name, "- File scope contained properties (none expected)"); } if (scope.props && scope.props.length > 0) { return callback("fail", name, "- QMLObjScope contained properties (none expected)"); } // Check the Obj Type for the props we created if (!obj.props.first) { return callback("fail", name, "- Obj did not contain property 'first'"); } if (!obj.props.second) { return callback("fail", name, "- Obj did not contain property 'second'"); } return callback("ok", name); }); });
test("QMLMemScope::hasProp() [Multiple Parent Scopes]", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var rootObj = new infer.Obj(null, "Root"); var rootObjScope = new plugin.QMLObjScope(fileScope, null, rootObj); var obj = new infer.Obj(null, "MyObject"); var objScope = new plugin.QMLObjScope(rootObjScope, null, obj); var scope = new plugin.QMLMemScope(objScope, null, fileScope); // Define a property on the Root Obj Type and Obj Type rootObj.defProp("notVisible", null); obj.defProp("visible", null); // Query the scope for the prop we created and make sure it returns the right one var prop = scope.hasProp("notVisible", true); if (prop) { return callback("fail", name, "- found property 'notVisible'"); } prop = scope.hasProp("visible", true); if (!prop) { return callback("fail", name, "- hasProp('visible') returned null"); } else if (prop.propertyName !== "visible") { return callback("fail", name, "- hasProp('visible') returned invalid property"); } return callback("ok", name); }); });
test("QMLMemScope::hasProp()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var obj = new infer.Obj(null, "MyObject"); var objScope = new plugin.QMLObjScope(fileScope, null, obj); var scope = new plugin.QMLMemScope(objScope, null, fileScope); // Define a property on the Obj Type and File Scope obj.defProp("first", null); fileScope.defProp("second", null); // Query the scope for the prop we created and make sure it returns the right one var prop = scope.hasProp("first", true); if (!prop) { return callback("fail", name, "- hasProp('first') returned null"); } else if (prop.propertyName !== "first") { return callback("fail", name, "- hasProp('first') returned invalid property"); } prop = scope.hasProp("second", true); if (!prop) { return callback("fail", name, "- hasProp('second') returned null"); } else if (prop.propertyName !== "second") { return callback("fail", name, "- hasProp('second') returned invalid property"); } return callback("ok", name); }); });
function isStealModule(text) { var ctx = new infer.Context([{steal:"fn() -> any()"}]), stealFound = false; infer.withContext(ctx, function() { var ast = infer.parse(text); infer.analyze(ast, "steal"); infer.findRefs(ast, ctx.topScope, "steal", ctx.topScope, function(ref) { stealFound = stealFound || !!ref; }); }); return stealFound; }
test("QMLJSScope::hasProp()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var idScope = new infer.Scope(null, "<qml-id>"); var jsScope = new infer.Scope(null, "<qml-js>"); var fnScope = new infer.Scope(null, "<qml-fn>"); var scope = new plugin.QMLJSScope(fileScope, null, idScope, jsScope, fnScope); // Define properties in each scope fileScope.defProp("first", null); idScope.defProp("second", null); jsScope.defProp("third", null); fnScope.defProp("fourth", null); scope.defProp("fifth", null); // Query the scope for the prop we created and make sure it returns the right one var prop = scope.hasProp("first", true); if (!prop) { return callback("fail", name, "- hasProp('first') returned null"); } else if (prop.propertyName !== "first") { return callback("fail", name, "- hasProp('first') returned invalid property"); } prop = scope.hasProp("second", true); if (!prop) { return callback("fail", name, "- hasProp('second') returned null"); } else if (prop.propertyName !== "second") { return callback("fail", name, "- hasProp('second') returned invalid property"); } prop = scope.hasProp("third", true); if (!prop) { return callback("fail", name, "- hasProp('third') returned null"); } else if (prop.propertyName !== "third") { return callback("fail", name, "- hasProp('third') returned invalid property"); } prop = scope.hasProp("fourth", true); if (!prop) { return callback("fail", name, "- hasProp('fourth') returned null"); } else if (prop.propertyName !== "fourth") { return callback("fail", name, "- hasProp('fourth') returned invalid property"); } prop = scope.hasProp("fifth", true); if (!prop) { return callback("fail", name, "- hasProp('fifth') returned null"); } else if (prop.propertyName !== "fifth") { return callback("fail", name, "- hasProp('fifth') returned invalid property"); } return callback("ok", name); }); });
test("QMLJSScope::gatherProperties()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test // Create the scope and objects to test var fileScope = new infer.Scope(); var idScope = new infer.Scope(null, "<qml-id>"); var jsScope = new infer.Scope(null, "<qml-js>"); var fnScope = new infer.Scope(null, "<qml-fn>"); var scope = new plugin.QMLJSScope(fileScope, null, idScope, jsScope, fnScope); // Define properties in each scope fileScope.defProp("fifth", null); idScope.defProp("first", null); jsScope.defProp("fourth", null); fnScope.defProp("third", null); scope.defProp("second", null); // Gather the properties and store them in the order they were received var props = []; scope.gatherProperties(function (prop, obj, depth) { props.push(prop); }); // Check the gathered properties for correctness (order matters) if (props.length !== 5) { return callback("fail", name, "- Invalid number of properties gathered (" + props.length + ")"); } if (props[0] !== "first") { return callback("fail", name, "- props[0] was not property 'first'"); } if (props[1] !== "second") { return callback("fail", name, "- props[1] was not property 'second'"); } if (props[2] !== "third") { return callback("fail", name, "- props[2] was not property 'third'"); } if (props[3] !== "fourth") { return callback("fail", name, "- props[3] was not property 'fourth'"); } if (props[4] !== "fifth") { return callback("fail", name, "- props[4] was not property 'fifth'"); } return callback("ok", name); }); });
test("QMLObjScope::removeProp()", function (server, callback, name) { infer.withContext(new infer.Context([], server), function () { // Create the scope and objects to test var fileScope = new infer.Scope(); var obj = new infer.Obj(null, "MyObject"); var scope = new plugin.QMLObjScope(fileScope, null, obj); // Define some properties scope.defProp("first", null); scope.defProp("second", null); // Remove the properties we defined scope.removeProp("first"); scope.removeProp("second"); // Check the Obj Type for the props we created if (obj.props && obj.props.length > 0) { return callback("fail", name, "- Obj contained properties (none expected)"); } return callback("ok", name); }); });
var createTernFile = function (name, code, options) { var wrap = isBoolean(options.wrap) ? options.wrap : false; var file = { name: name, text: code }; var context = new infer.Context(defs); infer.withContext(context, function () { file.ast = infer.parse(file.text, { directSourceFile: file, allowReturnOutsideFunction: true, allowImportExportEverywhere: true, ecmaVersion: 6 }); file.scope = context.topScope; if (wrap) { file.scope = buildWrappingScope(file.scope, file.name, file.ast); } infer.analyze(file.ast, file.text, file.scope); }); return file; };
function inferFile(filename, fileContents, baseLineNumber) { function addLink(url, node) { if (!(url in urls)) urls[url] = []; var lineNumber = baseLineNumber + require("acorn").getLineInfo(fileContents, node.start).line; var link = "/"+htmlLinks[filename]+"#line="; var found = false; for (var i in urls[url]) { if (urls[url][i].url.indexOf(link)==0) { var lineNumbers = urls[url][i].url.substr(link.length).split(","); if (lineNumbers.indexOf(lineNumber)<0) urls[url][i].url += ","+lineNumber; found = true; } } if (!found) urls[url].push({ url : link+lineNumber, title : fileTitles[filename]}); } var cx = new infer.Context(defs, null); infer.withContext(cx, function() { //console.log(JSON.stringify(filename)); var ast = infer.parse(fileContents, {}, {}); infer.analyze(ast, "file:"+filename /* just an id */); // find all calls require("acorn/dist/walk").simple(ast, { "CallExpression" : function(n) { var expr = infer.findExpressionAt(n.callee); var type = infer.expressionType(expr); // Try and handle 'require(...).foo) - this doesn't work for // var fs = require("fs") though. if (n.callee.type=="MemberExpression" && n.callee.object.type=="CallExpression" && n.callee.object.callee.type=="Identifier" && n.callee.object.callee.name=="require" && n.callee.object.arguments.length==1 && n.callee.object.arguments[0].type=="Literal") { var lib = n.callee.object.arguments[0].value; var name = n.callee.property.name; if (defs[0][lib] && defs[0][lib][name] && defs[0][lib][name]["!url"]) { // console.log(">>>>>>>>>>>>>>>"+lib+":"+name); // console.log(defs[0][lib][name], defs[0][lib][name]["!url"]); addLink(defs[0][lib][name]["!url"], n); } } // search prototype chain of type to try and find our call if (type.forward && type.types) { var name = type.forward[0].propName; type.types.forEach(function(t) { var def = undefined; while (t && !def) { if (t.props && name in t.props) def = t.props[name]; t = t.proto; } if (def) type = def; }); } if (type && type.types && type.types.length>0) { var url = type.types[0].url; if (url) addLink(url, n); } }}); }); }