1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-05 16:56:04 +02:00

Bug 481126 - Tern-QML Directory Imports

Added functionality to tern-qml that allows it to recognize directory
imports of the form:  import "<directory>" [as <Qualifier>].  Content
assist and find definitions also work for these new imports.  Moreover,
fixed the QML Scoping to be easier to handle in the future by defining
new Scope Objects specifically for QML.  Finally, used JS Hint and
Beautify to have a more uniform coding style between all the files of
acorn-qml and tern-qml.

Also fixed up the HTML Demo to allow editing of multiple files to show
the new imports.

Change-Id: I2cdd18b1b8765400f6b24145f0677127a221fe10
Signed-off-by: Matthew Bastien <mbastien@blackberry.com>
This commit is contained in:
Matthew Bastien 2015-12-03 15:24:36 -05:00 committed by Gerrit Code Review @ Eclipse.org
parent 3ec33023c3
commit dd3815bb91
20 changed files with 2562 additions and 868 deletions

View file

@ -8,18 +8,14 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
// This will only be visible globally if we are in a browser environment
var acornQML;
(function (mod) { (function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("./inject.js"), require("acorn")); return mod(require("./inject.js"), require("acorn"));
if (typeof define == "function" && define.amd) // AMD if (typeof define == "function" && define.amd) // AMD
return define(["./inject.js", "acorn/dist/acorn"], mod); return define(["./inject.js", "acorn/dist/acorn"], mod);
acornQML = mod(injectQML, acorn); // Plain browser env mod(acornQMLInjector, acorn); // Plain browser env
})(function (injectQML, acorn) { })(function (acornQMLInjector, acorn) {
'use strict'; 'use strict';
return injectQML(acorn); acornQMLInjector.inject(acorn);
}) });

View file

@ -8,20 +8,16 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
(function (root, mod) {
// This will only be visible globally if we are in a browser environment
var injectQML;
(function (mod) {
if (typeof exports === "object" && typeof module === "object") // CommonJS if (typeof exports === "object" && typeof module === "object") // CommonJS
return module.exports = mod(); return mod(exports);
if (typeof define === "function" && define.amd) // AMD if (typeof define === "function" && define.amd) // AMD
return define([], mod); return define(["exports"], mod);
injectQML = mod(); // Plain browser env mod(root.acornQMLInjector || (root.acornQMLInjector = {})); // Plain browser env
})(function () { })(this, function (exports) {
'use strict'; 'use strict';
return function (acorn) { exports.inject = function (acorn) {
// Acorn token types // Acorn token types
var tt = acorn.tokTypes; var tt = acorn.tokTypes;
@ -88,7 +84,7 @@ var injectQML;
* the type import or pragma * the type import or pragma
*/ */
pp.qml_parseHeaderStatements = function () { pp.qml_parseHeaderStatements = function () {
var node = this.startNode() var node = this.startNode();
node.statements = []; node.statements = [];
var loop = true; var loop = true;
@ -103,7 +99,7 @@ var injectQML;
} }
return this.finishNode(node, "QMLHeaderStatements"); return this.finishNode(node, "QMLHeaderStatements");
} };
/* /*
* Parses a QML Pragma statement of the form: * Parses a QML Pragma statement of the form:
@ -115,7 +111,7 @@ var injectQML;
node.id = this.parseIdent(false); node.id = this.parseIdent(false);
this.semicolon(); this.semicolon();
return this.finishNode(node, "QMLPragmaStatement"); return this.finishNode(node, "QMLPragmaStatement");
} };
/* /*
* Parses a QML Import statement of the form: * Parses a QML Import statement of the form:
@ -180,7 +176,7 @@ var injectQML;
node.raw = this.input.slice(this.start, this.end); node.raw = this.input.slice(this.start, this.end);
node.value = this.value; node.value = this.value;
var matches; var matches;
if (matches = /(\d+)\.(\d+)/.exec(node.raw)) { if ((matches = /(\d+)\.(\d+)/.exec(node.raw))) {
node.major = parseInt(matches[1]); node.major = parseInt(matches[1]);
node.minor = parseInt(matches[2]); node.minor = parseInt(matches[2]);
this.next(); this.next();
@ -189,7 +185,7 @@ var injectQML;
} }
return this.finishNode(node, "QMLVersionLiteral"); return this.finishNode(node, "QMLVersionLiteral");
} };
/* /*
* Parses a QML Qualifier of the form: * Parses a QML Qualifier of the form:
@ -200,7 +196,7 @@ var injectQML;
this.expectContextual(qtt._as); this.expectContextual(qtt._as);
node.id = this.qml_parseIdent(false); node.id = this.qml_parseIdent(false);
return this.finishNode(node, "QMLQualifier"); return this.finishNode(node, "QMLQualifier");
} };
/* /*
* Parses a QML Object Literal of the form: * Parses a QML Object Literal of the form:
@ -217,7 +213,7 @@ var injectQML;
} }
node.body = this.qml_parseMemberBlock(); node.body = this.qml_parseMemberBlock();
return this.finishNode(node, "QMLObjectLiteral"); return this.finishNode(node, "QMLObjectLiteral");
} };
/* /*
* Parses a QML Member Block of the form: * Parses a QML Member Block of the form:
@ -231,7 +227,7 @@ var injectQML;
node.members.push(this.qml_parseMember()); node.members.push(this.qml_parseMember());
} }
return this.finishNode(node, "QMLMemberBlock"); return this.finishNode(node, "QMLMemberBlock");
} };
/* /*
* Parses a QML Member which can be one of the following: * Parses a QML Member which can be one of the following:
@ -250,7 +246,7 @@ var injectQML;
return this.qml_parseFunctionMember(); return this.qml_parseFunctionMember();
} }
return this.qml_parseObjectLiteralOrPropertyBinding(); return this.qml_parseObjectLiteralOrPropertyBinding();
} };
/* /*
* Parses a JavaScript function as a member of a QML Object Literal * Parses a JavaScript function as a member of a QML Object Literal
@ -259,7 +255,7 @@ var injectQML;
var node = this.startNode(); var node = this.startNode();
this.expect(tt._function); this.expect(tt._function);
return this.parseFunction(node, true); return this.parseFunction(node, true);
} };
/* /*
* Parses a QML Object Literal or Property Binding depending on the tokens found. * Parses a QML Object Literal or Property Binding depending on the tokens found.
@ -278,7 +274,7 @@ var injectQML;
return this.qml_parsePropertyBinding(node); return this.qml_parsePropertyBinding(node);
} }
this.unexpected(); this.unexpected();
} };
/* /*
* Parses a QML Property of the form: * Parses a QML Property of the form:
@ -294,7 +290,7 @@ var injectQML;
this.expect(tt.colon); this.expect(tt.colon);
node.binding = this.qml_parseBinding(); node.binding = this.qml_parseBinding();
return this.finishNode(node, "QMLPropertyBinding"); return this.finishNode(node, "QMLPropertyBinding");
} };
/* /*
* Parses a QML Signal Definition of the form: * Parses a QML Signal Definition of the form:
@ -325,7 +321,7 @@ var injectQML;
this.qml_parseSignalParams(node); this.qml_parseSignalParams(node);
this.semicolon(); this.semicolon();
return this.finishNode(node, "QMLSignalDefinition"); return this.finishNode(node, "QMLSignalDefinition");
} };
/* /*
* Parses QML Signal Parameters of the form: * Parses QML Signal Parameters of the form:
@ -344,7 +340,7 @@ var injectQML;
this.expect(tt.parenR); this.expect(tt.parenR);
} }
} }
} };
/* /*
* Parses a QML Property Declaration (or Alias) of the form: * Parses a QML Property Declaration (or Alias) of the form:
@ -354,10 +350,10 @@ var injectQML;
var node = this.startNode(); var node = this.startNode();
// Parse 'default' or 'readonly' // Parse 'default' or 'readonly'
node["default"] = false; node.default = false;
node["readonly"] = false; node.readonly = false;
if (this.eat(tt._default)) { if (this.eat(tt._default)) {
node["default"] = true; node.default = true;
} else if (this.isContextual(qtt._readonly)) { } else if (this.isContextual(qtt._readonly)) {
// Parse as a qualified id in case this is not a property declaration // Parse as a qualified id in case this is not a property declaration
var readonly = this.qml_parseQualifiedId(true); var readonly = this.qml_parseQualifiedId(true);
@ -367,7 +363,7 @@ var injectQML;
node.id = readonly; node.id = readonly;
return this.qml_parseObjectLiteralOrPropertyBinding(node); return this.qml_parseObjectLiteralOrPropertyBinding(node);
} }
node["readonly"] = true; node.readonly = true;
} else { } else {
// Readonly keyword is a qualified ID. This is not a property declaration. // Readonly keyword is a qualified ID. This is not a property declaration.
node.id = readonly; node.id = readonly;
@ -377,22 +373,22 @@ var injectQML;
// Parse as a qualified id in case this is not a property declaration // Parse as a qualified id in case this is not a property declaration
var property = this.qml_parseQualifiedId(true); var property = this.qml_parseQualifiedId(true);
if (property.parts.length === 1 || node["default"] || node["readonly"]) { if (property.parts.length === 1 || node.default || node.readonly) {
if (property.name !== qtt._property) { if (property.name !== qtt._property) {
this.unexpected(); this.unexpected();
} }
if (this.type === tt.colon || this.type === tt.braceL) { if (this.type === tt.colon || this.type === tt.braceL) {
// This is a property binding or object literal. // This is a property binding or object literal.
node["default"] = undefined; node.default = undefined;
node["readonly"] = undefined; node.readonly = undefined;
node.id = property; node.id = property;
return this.qml_parseObjectLiteralOrPropertyBinding(node); return this.qml_parseObjectLiteralOrPropertyBinding(node);
} }
} else { } else {
// Property keyword is a qualified ID. This is not a property declaration. // Property keyword is a qualified ID. This is not a property declaration.
node["default"] = undefined; node.default = undefined;
node["readonly"] = undefined; node.readonly = undefined;
node.id = property; node.id = property;
return this.qml_parseObjectLiteralOrPropertyBinding(node); return this.qml_parseObjectLiteralOrPropertyBinding(node);
} }
@ -407,7 +403,7 @@ var injectQML;
} }
return this.finishNode(node, "QMLPropertyDeclaration"); return this.finishNode(node, "QMLPropertyDeclaration");
} };
/* /*
* Parses one of the following possibilities for a QML Property assignment: * Parses one of the following possibilities for a QML Property assignment:
@ -422,7 +418,7 @@ var injectQML;
// test: QMLObject.QualifiedId { } // test: QMLObject.QualifiedId { }
return this.qml_parseScriptBinding(); return this.qml_parseScriptBinding();
} };
/* /*
* Parses one of the following Script Bindings: * Parses one of the following Script Bindings:
@ -440,7 +436,7 @@ var injectQML;
this.semicolon(); this.semicolon();
} }
return this.finishNode(node, "QMLScriptBinding"); return this.finishNode(node, "QMLScriptBinding");
} };
/* /*
* Parses a QML Statement Block of the form: * Parses a QML Statement Block of the form:
@ -454,7 +450,7 @@ var injectQML;
node.statements.push(this.parseStatement(true, false)); node.statements.push(this.parseStatement(true, false));
} }
return this.finishNode(node, "QMLStatementBlock"); return this.finishNode(node, "QMLStatementBlock");
} };
/* /*
* Parses a QML Type which can be either a Qualified ID or a primitive type keyword. * Parses a QML Type which can be either a Qualified ID or a primitive type keyword.
@ -468,7 +464,7 @@ var injectQML;
return this.qml_parseQualifiedId(false); return this.qml_parseQualifiedId(false);
} }
this.unexpected(); this.unexpected();
} };
/* /*
* Parses a Qualified ID of the form: * Parses a Qualified ID of the form:
@ -494,7 +490,7 @@ var injectQML;
} }
return this.finishNode(node, "QMLQualifiedID"); return this.finishNode(node, "QMLQualifiedID");
} };
/* /*
* Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual' * Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
@ -511,7 +507,7 @@ var injectQML;
} }
} }
return this.parseIdent(liberal); return this.parseIdent(liberal);
} };
/* /*
* Returns whether or not a given token type and name can be a QML Identifier. * Returns whether or not a given token type and name can be a QML Identifier.
@ -520,13 +516,13 @@ var injectQML;
pp.qml_isIdent = function (type, name) { pp.qml_isIdent = function (type, name) {
if (type === tt.name) { if (type === tt.name) {
var key; var key;
if (key = keywords[name]) { if ((key = keywords[name])) {
return key.isQMLContextual return key.isQMLContextual;
} }
return true; return true;
} }
return false; return false;
} };
/* /*
* Returns whether or not the current token is a QML primitive type and consumes * Returns whether or not the current token is a QML primitive type and consumes
@ -538,7 +534,7 @@ var injectQML;
return true; return true;
} }
return false; return false;
} };
/* /*
* Returns whether or not the current token is a QML primitive type. * Returns whether or not the current token is a QML primitive type.
@ -550,12 +546,12 @@ var injectQML;
if (type === tt.name) { if (type === tt.name) {
var key; var key;
if (key = keywords[name]) { if ((key = keywords[name])) {
return key.isPrimitive; return key.isPrimitive;
} }
} }
return false; return false;
} };
acorn.plugins.qml = function (instance) { acorn.plugins.qml = function (instance) {
@ -589,8 +585,8 @@ var injectQML;
return this.finishNode(node, "QMLProgram"); return this.finishNode(node, "QMLProgram");
}; };
}); });
} };
return acorn; return acorn;
}; };
}) });

View file

@ -8,18 +8,14 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
// This will only be visible globally if we are in a browser environment
var acornQMLLoose;
(function (mod) { (function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("./inject.js"), require("acorn"), require("acorn/dist/acorn_loose")); return mod(require("./inject.js"), require("acorn"), require("acorn/dist/acorn_loose"));
if (typeof define == "function" && define.amd) // AMD if (typeof define == "function" && define.amd) // AMD
return define(["./inject.js", "acorn", "acorn/dist/acorn_loose"], mod); return define(["./inject.js", "acorn", "acorn/dist/acorn_loose"], mod);
acornQMLLoose = mod(injectQMLLoose, acorn, acorn); // Plain browser env mod(acornQMLLooseInjector, acorn, acorn); // Plain browser env
})(function (injectQMLLoose, acorn, acorn_loose) { })(function (acornQMLLooseInjector, acorn, acorn_loose) {
"use strict"; "use strict";
return injectQMLLoose(acorn); acornQMLLooseInjector.inject(acorn);
}) });

View file

@ -12,16 +12,16 @@
// This will only be visible globally if we are in a browser environment // This will only be visible globally if we are in a browser environment
var injectQMLLoose; var injectQMLLoose;
(function (mod) { (function (root, mod) {
if (typeof exports === "object" && typeof module === "object") // CommonJS if (typeof exports === "object" && typeof module === "object") // CommonJS
return module.exports = mod(); return mod(module.exports);
if (typeof define === "function" && define.amd) // AMD if (typeof define === "function" && define.amd) // AMD
return define([], mod); return define(["exports"], mod);
injectQMLLoose = mod(); // Plain browser env mod(root.acornQMLLooseInjector || (root.acornQMLLooseInjector = {})); // Plain browser env
})(function () { })(this, function (exports) {
"use strict"; "use strict";
return function (acorn) { exports.inject = function (acorn) {
// Acorn token types // Acorn token types
var tt = acorn.tokTypes; var tt = acorn.tokTypes;
@ -38,7 +38,7 @@ var injectQMLLoose;
* the type import or pragma * the type import or pragma
*/ */
lp.qml_parseHeaderStatements = function () { lp.qml_parseHeaderStatements = function () {
var node = this.startNode() var node = this.startNode();
node.statements = []; node.statements = [];
var loop = true; var loop = true;
@ -53,7 +53,7 @@ var injectQMLLoose;
} }
return this.finishNode(node, "QMLHeaderStatements"); return this.finishNode(node, "QMLHeaderStatements");
} };
/* /*
* Parses a QML Pragma statement of the form: * Parses a QML Pragma statement of the form:
@ -65,7 +65,7 @@ var injectQMLLoose;
node.id = this.parseIdent(false); node.id = this.parseIdent(false);
this.semicolon(); this.semicolon();
return this.finishNode(node, "QMLPragmaStatement"); return this.finishNode(node, "QMLPragmaStatement");
} };
/* /*
* Parses a QML Import statement of the form: * Parses a QML Import statement of the form:
@ -122,7 +122,7 @@ var injectQMLLoose;
node.value = this.tok.value; node.value = this.tok.value;
var matches; var matches;
if (this.tok.type === tt.num) { if (this.tok.type === tt.num) {
if (matches = /(\d+)\.(\d+)/.exec(node.raw)) { if ((matches = /(\d+)\.(\d+)/.exec(node.raw))) {
node.major = parseInt(matches[1]); node.major = parseInt(matches[1]);
node.minor = parseInt(matches[2]); node.minor = parseInt(matches[2]);
this.next(); this.next();
@ -139,7 +139,7 @@ var injectQMLLoose;
} }
return this.finishNode(node, "QMLVersionLiteral"); return this.finishNode(node, "QMLVersionLiteral");
} };
/* /*
* Parses a QML Qualifier of the form: * Parses a QML Qualifier of the form:
@ -150,7 +150,7 @@ var injectQMLLoose;
this.expectContextual(qtt._as); this.expectContextual(qtt._as);
node.id = this.qml_parseIdent(false); node.id = this.qml_parseIdent(false);
return this.finishNode(node, "QMLQualifier"); return this.finishNode(node, "QMLQualifier");
} };
/* /*
* Parses a QML Object Literal of the form: * Parses a QML Object Literal of the form:
@ -163,7 +163,7 @@ var injectQMLLoose;
node.id = this.qml_parseQualifiedId(false); node.id = this.qml_parseQualifiedId(false);
node.body = this.qml_parseMemberBlock(); node.body = this.qml_parseMemberBlock();
return this.finishNode(node, "QMLObjectLiteral"); return this.finishNode(node, "QMLObjectLiteral");
} };
/* /*
* Parses a QML Member Block of the form: * Parses a QML Member Block of the form:
@ -184,7 +184,7 @@ var injectQMLLoose;
this.popCx(); this.popCx();
this.eat(tt.braceR); this.eat(tt.braceR);
return this.finishNode(node, "QMLMemberBlock"); return this.finishNode(node, "QMLMemberBlock");
} };
/* /*
* Parses a QML Member which can be one of the following: * Parses a QML Member which can be one of the following:
@ -222,7 +222,7 @@ var injectQMLLoose;
} }
// ignore the current token if it didn't pass the previous tests // ignore the current token if it didn't pass the previous tests
this.next(); this.next();
} };
/* /*
* Parses a JavaScript function as a member of a QML Object Literal * Parses a JavaScript function as a member of a QML Object Literal
@ -231,7 +231,7 @@ var injectQMLLoose;
var node = this.startNode(); var node = this.startNode();
this.expect(tt._function); this.expect(tt._function);
return this.qml_parseFunction(node, true); return this.qml_parseFunction(node, true);
} };
/* /*
* QML version of 'parseFunction' needed to have proper error tolerant parsing * QML version of 'parseFunction' needed to have proper error tolerant parsing
@ -250,7 +250,7 @@ var injectQMLLoose;
node.body = this.parseBlock(); node.body = this.parseBlock();
} else { } else {
if (this.options.locations) { if (this.options.locations) {
node.body = this.startNodeAt([ this.last.end, this.last.loc.end ]) node.body = this.startNodeAt([ this.last.end, this.last.loc.end ]);
} else { } else {
node.body = this.startNodeAt(this.last.end); node.body = this.startNodeAt(this.last.end);
} }
@ -258,7 +258,7 @@ var injectQMLLoose;
this.finishNode(node.body, "BlockStatement"); this.finishNode(node.body, "BlockStatement");
} }
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
} };
/* /*
* Parses a QML Object Literal or Property Binding depending on the tokens found. * Parses a QML Object Literal or Property Binding depending on the tokens found.
@ -282,7 +282,7 @@ var injectQMLLoose;
return this.qml_parsePropertyBinding(); return this.qml_parsePropertyBinding();
} }
return null; return null;
} };
/* /*
* Parses a QML Property of the form: * Parses a QML Property of the form:
@ -295,7 +295,7 @@ var injectQMLLoose;
this.expect(tt.colon); this.expect(tt.colon);
node.binding = this.qml_parseBinding(start); node.binding = this.qml_parseBinding(start);
return this.finishNode(node, "QMLPropertyBinding"); return this.finishNode(node, "QMLPropertyBinding");
} };
/* /*
* Parses a QML Signal Definition of the form: * Parses a QML Signal Definition of the form:
@ -315,13 +315,13 @@ var injectQMLLoose;
this.qml_parseSignalParams(node); this.qml_parseSignalParams(node);
this.semicolon(); this.semicolon();
return this.finishNode(node, "QMLSignalDefinition"); return this.finishNode(node, "QMLSignalDefinition");
} };
/* /*
* Checks if the given node is a dummy identifier * Checks if the given node is a dummy identifier
*/ */
function isDummy(node) { function isDummy(node) {
return node.name === "✖" return node.name === "✖";
} }
/* /*
@ -329,8 +329,8 @@ var injectQMLLoose;
* [(<Type> <Identifier> [',' <Type> <Identifier>]* )]? * [(<Type> <Identifier> [',' <Type> <Identifier>]* )]?
*/ */
lp.qml_parseSignalParams = function (node) { lp.qml_parseSignalParams = function (node) {
this.pushCx() this.pushCx();
var indent = this.curIndent, line = this.curLineStart var indent = this.curIndent, line = this.curLineStart;
node.params = []; node.params = [];
if (this.eat(tt.parenL)) { if (this.eat(tt.parenL)) {
while (!this.closes(tt.parenR, indent + 1, line)) { while (!this.closes(tt.parenR, indent + 1, line)) {
@ -352,15 +352,15 @@ var injectQMLLoose;
} }
this.eat(tt.comma); this.eat(tt.comma);
} }
this.popCx() this.popCx();
if (!this.eat(tt.parenR)) { if (!this.eat(tt.parenR)) {
// If there is no closing brace, make the node span to the start // If there is no closing brace, make the node span to the start
// of the next token (this is useful for Tern) // of the next token (this is useful for Tern)
this.last.end = this.tok.start this.last.end = this.tok.start;
if (this.options.locations) this.last.loc.end = this.tok.loc.start if (this.options.locations) this.last.loc.end = this.tok.loc.start;
} }
} }
} };
/* /*
* Parses a QML Property Declaration (or Alias) of the form: * Parses a QML Property Declaration (or Alias) of the form:
@ -368,25 +368,26 @@ var injectQMLLoose;
*/ */
lp.qml_parsePropertyDeclaration = function () { lp.qml_parsePropertyDeclaration = function () {
var node = this.startNode(); var node = this.startNode();
var objOrBind = null;
// Parse 'default' or 'readonly' // Parse 'default' or 'readonly'
node["default"] = false; node.default = false;
node["readonly"] = false; node.readonly = false;
if (this.eat(tt._default)) { if (this.eat(tt._default)) {
node["default"] = true; node.default = true;
} else if (this.isContextual(qtt._readonly)) { } else if (this.isContextual(qtt._readonly)) {
var objOrBind = this.qml_parseObjectLiteralOrPropertyBinding(); objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
if (objOrBind) { if (objOrBind) {
objOrBind["default"] = undefined; objOrBind.default = undefined;
objOrBind["readonly"] = undefined; objOrBind.readonly = undefined;
return objOrBind; return objOrBind;
} }
this.expectContextual(qtt._readonly); this.expectContextual(qtt._readonly);
node["readonly"] = true; node.readonly = true;
} }
if (!node["default"] && !node["readonly"]) { if (!node.default && !node.readonly) {
var objOrBind = this.qml_parseObjectLiteralOrPropertyBinding(); objOrBind = this.qml_parseObjectLiteralOrPropertyBinding();
if (objOrBind) { if (objOrBind) {
return objOrBind; return objOrBind;
} }
@ -408,7 +409,7 @@ var injectQMLLoose;
} }
return this.finishNode(node, "QMLPropertyDeclaration"); return this.finishNode(node, "QMLPropertyDeclaration");
} };
/* /*
* Parses one of the following possibilities for a QML Property assignment: * Parses one of the following possibilities for a QML Property assignment:
@ -437,7 +438,7 @@ var injectQMLLoose;
} else { } else {
return this.qml_parseScriptBinding(start); return this.qml_parseScriptBinding(start);
} }
} };
/* /*
* Parses one of the following Script Bindings: * Parses one of the following Script Bindings:
@ -458,7 +459,7 @@ var injectQMLLoose;
} }
// If this node consumed valid syntax, reset its start position // If this node consumed valid syntax, reset its start position
if (!node.script.type === "Identifier" || node.script.name !== "✖") { if (node.script.type !== "Identifier" || node.script.name !== "✖") {
if (node.loc) { if (node.loc) {
node.loc.start = node.script.loc.start; node.loc.start = node.script.loc.start;
} }
@ -470,7 +471,7 @@ var injectQMLLoose;
} }
return this.finishNode(node, "QMLScriptBinding"); return this.finishNode(node, "QMLScriptBinding");
} };
/* /*
* Parses a QML Statement Block of the form: * Parses a QML Statement Block of the form:
@ -489,7 +490,7 @@ var injectQMLLoose;
this.popCx(); this.popCx();
this.eat(tt.braceR); this.eat(tt.braceR);
return this.finishNode(node, "QMLStatementBlock"); return this.finishNode(node, "QMLStatementBlock");
} };
/* /*
* Parses a QML Type which can be either a Qualified ID or a primitive type keyword. * Parses a QML Type which can be either a Qualified ID or a primitive type keyword.
@ -501,7 +502,7 @@ var injectQMLLoose;
} else { } else {
return this.qml_parseQualifiedId(false); return this.qml_parseQualifiedId(false);
} }
} };
/* /*
* Parses a Qualified ID of the form: * Parses a Qualified ID of the form:
@ -527,7 +528,7 @@ var injectQMLLoose;
} }
return this.finishNode(node, "QMLQualifiedID"); return this.finishNode(node, "QMLQualifiedID");
} };
/* /*
* Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual' * Parses an Identifier in a QML Context. That is, this method uses 'isQMLContextual'
@ -544,7 +545,7 @@ var injectQMLLoose;
} }
} }
return this.parseIdent(); return this.parseIdent();
} };
/* /*
* Checks the next token to see if it matches the given contextual keyword. If the * Checks the next token to see if it matches the given contextual keyword. If the
@ -552,14 +553,14 @@ var injectQMLLoose;
* and jumps ahead if it was found there. Returns whether or not the keyword was found. * and jumps ahead if it was found there. Returns whether or not the keyword was found.
*/ */
lp.expectContextual = function(name) { lp.expectContextual = function(name) {
if (this.eatContextual(name)) return true if (this.eatContextual(name)) return true;
for (var i = 1; i <= 2; i++) { for (var i = 1; i <= 2; i++) {
if (this.lookAhead(i).type == tt.name && this.lookAhead(i).value === name) { if (this.lookAhead(i).type == tt.name && this.lookAhead(i).value === name) {
for (var j = 0; j < i; j++) this.next() for (var j = 0; j < i; j++) this.next();
return true return true;
} }
} }
} };
// Functions left un-changed from the main parser // Functions left un-changed from the main parser
lp.qml_isIdent = pp.qml_isIdent; lp.qml_isIdent = pp.qml_isIdent;
@ -592,8 +593,8 @@ var injectQMLLoose;
return this.finishNode(node, "QMLProgram"); return this.finishNode(node, "QMLProgram");
}; };
}); });
} };
return acorn; return acorn;
}; };
}) });

View file

@ -8,7 +8,7 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
var tests = []; var tests = [];
@ -31,10 +31,10 @@ exports.runTests = function(config, callback) {
try { try {
var testOpts = test.options || {locations: true}; var testOpts = test.options || {locations: true};
var expected = {}; var expected = {};
if (expected.onComment = testOpts.onComment) { if ((expected.onComment = testOpts.onComment)) {
testOpts.onComment = [] testOpts.onComment = [];
} }
if (expected.onToken = testOpts.onToken) { if ((expected.onToken = testOpts.onToken)) {
testOpts.onToken = []; testOpts.onToken = [];
} }
testOpts.plugins = { qml: true }; testOpts.plugins = { qml: true };
@ -87,6 +87,7 @@ function addPath(str, pt) {
} }
var misMatch = exports.misMatch = function(exp, act) { var misMatch = exports.misMatch = function(exp, act) {
var mis = null;
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) { if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act); if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
} else if (exp instanceof RegExp || act instanceof RegExp) { } else if (exp instanceof RegExp || act instanceof RegExp) {
@ -96,12 +97,12 @@ var misMatch = exports.misMatch = function(exp, act) {
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act); if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length; if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
for (var i = 0; i < act.length; ++i) { for (var i = 0; i < act.length; ++i) {
var mis = misMatch(exp[i], act[i]); mis = misMatch(exp[i], act[i]);
if (mis) return addPath(mis, i); if (mis) return addPath(mis, i);
} }
} else { } else {
for (var prop in exp) { for (var prop in exp) {
var mis = misMatch(exp[prop], act[prop]); mis = misMatch(exp[prop], act[prop]);
if (mis) return addPath(mis, prop); if (mis) return addPath(mis, prop);
} }
} }

View file

@ -8,11 +8,18 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
// Get the driver and test code
var driver = require("./driver.js"); var driver = require("./driver.js");
require("./tests-qml.js"); require("./tests-qml.js");
// Get and inject the QML plugin into Acorn
var acorn = require("acorn");
require("acorn/dist/acorn_loose");
require("..");
require("../loose");
function group(name) { function group(name) {
if (typeof console === "object" && console.group) { if (typeof console === "object" && console.group) {
console.group(name); console.group(name);
@ -32,7 +39,7 @@ function log(title, message) {
var stats, modes = { var stats, modes = {
Normal: { Normal: {
config: { config: {
parse: require("..").parse, parse: acorn.parse,
normal: true, normal: true,
filter: function (test) { filter: function (test) {
var opts = test.options || {}; var opts = test.options || {};
@ -42,7 +49,7 @@ var stats, modes = {
}, },
Loose: { Loose: {
config: { config: {
parse: require("../loose").parse_dammit, parse: acorn.parse_dammit,
loose: true, loose: true,
filter: function (test) { filter: function (test) {
var opts = test.options || {}; var opts = test.options || {};
@ -63,9 +70,9 @@ for (var name in modes) {
group(name); group(name);
var mode = modes[name]; var mode = modes[name];
stats = mode.stats = {testsRun: 0, failed: 0}; stats = mode.stats = {testsRun: 0, failed: 0};
var t0 = +new Date; var t0 = +new Date();
driver.runTests(mode.config, report); driver.runTests(mode.config, report);
mode.stats.duration = +new Date - t0; mode.stats.duration = +new Date() - t0;
groupEnd(); groupEnd();
} }

View file

@ -8,11 +8,12 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
var test = require("./driver.js").test; var driver = require("./driver.js");
var testFail = require("./driver.js").testFail; var test = driver.test;
var tokTypes = require("../").tokTypes; var testFail = driver.testFail;
var tokTypes = driver.tokTypes;
testFail('', "QML only supports ECMA Script Language Specification 5 or older", testFail('', "QML only supports ECMA Script Language Specification 5 or older",
{ locations: true, ecmaVersion: 6, allowReserved: false }); { locations: true, ecmaVersion: 6, allowReserved: false });
@ -3241,7 +3242,7 @@ function program(headerStatements, rootObject) {
statements: headerStatements || [] statements: headerStatements || []
}, },
rootObject: rootObject || null rootObject: rootObject || null
} };
} }
/* /*

View file

@ -10,7 +10,7 @@
*******************************************************************************/ *******************************************************************************/
(function (mod) { (function (mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS if (typeof exports == "object" && typeof module == "object") // CommonJS
return module.exports = mod(require("acorn/dist/walk")); return mod(require("acorn/dist/walk"));
if (typeof define == "function" && define.amd) // AMD if (typeof define == "function" && define.amd) // AMD
return define(["acorn/dist/walk"], mod); return define(["acorn/dist/walk"], mod);
mod(acorn.walk); // Plain browser env mod(acorn.walk); // Plain browser env
@ -18,53 +18,59 @@
"use strict"; "use strict";
function skipThrough(node, st, c) { function skipThrough(node, st, c) {
c(node, st) c(node, st);
} }
function ignore(node, st, c) {} function ignore(node, st, c) {}
var base = walk.base; function extendWalk(walker, funcs) {
base["QMLProgram"] = function (node, st, c) { for (var prop in funcs) {
c(node.headerStatements, st); walker[prop] = funcs[prop];
if (node.rootObject) {
c(node.rootObject, st, "QMLRootObject");
} }
};
base["QMLHeaderStatements"] = function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "QMLHeaderStatement");
}
};
base["QMLHeaderStatement"] = skipThrough;
base["QMLImportStatement"] = ignore;
base["QMLPragmaStatement"] = ignore;
base["QMLRootObject"] = skipThrough;
base["QMLObjectLiteral"] = function (node, st, c) {
c(node.body, st);
};
base["QMLMemberBlock"] = function (node, st, c) {
for (var i = 0; i < node.members.length; i++) {
c(node.members[i], st, "QMLMember");
}
};
base["QMLMember"] = skipThrough;
base["QMLPropertyDeclaration"] = function (node, st, c) {
if (node.binding) {
c(node.binding, st);
}
};
base["QMLSignalDefinition"] = ignore;
base["QMLPropertyBinding"] = function (node, st, c) {
c(node.binding, st);
};
base["QMLScriptBinding"] = function (node, st, c) {
c(node.script, st);
} }
base["QMLQualifiedID"] = ignore;
base["QMLStatementBlock"] = function (node, st, c) { extendWalk(walk.base, {
for (var i = 0; i < node.statements.length; i++) { QMLProgram: function (node, st, c) {
c(node.statements[i], st, "Statement"); c(node.headerStatements, st);
if (node.rootObject) {
c(node.rootObject, st, "QMLRootObject");
}
},
QMLHeaderStatements: function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "QMLHeaderStatement");
}
},
QMLHeaderStatement: skipThrough,
QMLImportStatement: ignore,
QMLPragmaStatement: ignore,
QMLRootObject: skipThrough,
QMLObjectLiteral: function (node, st, c) {
c(node.body, st);
},
QMLMemberBlock: function (node, st, c) {
for (var i = 0; i < node.members.length; i++) {
c(node.members[i], st, "QMLMember");
}
},
QMLMember: skipThrough,
QMLPropertyDeclaration: function (node, st, c) {
if (node.binding) {
c(node.binding, st);
}
},
QMLSignalDefinition: ignore,
QMLPropertyBinding: function (node, st, c) {
c(node.binding, st);
},
QMLScriptBinding: function (node, st, c) {
c(node.script, st);
},
QMLQualifiedID: ignore,
QMLStatementBlock: function (node, st, c) {
for (var i = 0; i < node.statements.length; i++) {
c(node.statements[i], st, "Statement");
}
} }
}; });
return walk; });
})

View file

@ -1,5 +1,4 @@
(function() { var ecma5 = {
var def = {
"!name": "ecma5", "!name": "ecma5",
"!define": {"Error.prototype": "Error.prototype"}, "!define": {"Error.prototype": "Error.prototype"},
"Infinity": { "Infinity": {
@ -964,6 +963,4 @@ var def = {
"!url": "https://developer.mozilla.org/en-US/docs/JSON", "!url": "https://developer.mozilla.org/en-US/docs/JSON",
"!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference." "!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."
} }
} }
CodeMirror.tern.addDef(def);
})();

View file

@ -0,0 +1,91 @@
.CodeMirror {
border: 1px solid silver;
height: 400px;
line-height: 1.3;
font-size: 13pt;
font-family: "Ubuntu Mono", monospace;
z-index: 2;
}
.CodeMirror pre {
padding: 0 9px;
}
.CodeMirror-linenumber {
font-size: 80%;
padding-top: 2px;
}
ul.tabs {
list-style: none;
margin: 0 0 -1px 0;
padding: 0 0 0 37px;
font-family: "Ubuntu Mono", monospace;
overflow: hidden;
}
ul.tabs li {
font-size: 11pt;
color: #777;
cursor: pointer;
margin: 0 2px 0 0;
padding: 2px 10px 5px;
border: 1px solid silver;
border-bottom-width: 0px;
background: #f3f3f3;
display: inline-block;
z-index: 1;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
position: relative;
}
ul.tabs li:hover {
color: #444;
}
ul.tabs li.selected {
background: white;
color: #222;
z-index: 3;
cursor: default;
}
ul.tabs li:before,
ul.tabs li:after {
position: absolute;
bottom: 0;
width: 6px;
height: 6px;
content: " ";
border: 1px solid silver;
}
ul.tabs li:before {
left: -7px;
border-bottom-right-radius: 6px;
border-width: 0 1px 1px 0;
box-shadow: 2px 2px 0 #f3f3f3;
}
ul.tabs li:after {
right: -7px;
border-bottom-left-radius: 6px;
border-width: 0 0 1px 1px;
box-shadow: -2px 2px 0 #f3f3f3;
}
ul.tabs li.selected:before {
box-shadow: 2px 2px 0 white;
}
ul.tabs li.selected:after {
box-shadow: -2px 2px 0 white;
}
#menus {
position: absolute;
right: 0;
top: 0;
}
#menus select {
font-family: "Ubuntu Mono", monospace;
font-size: 11pt;
width: 8em;
}
.CodeMirror div.CodeMirror-cursor {
border-left: 2px solid #444;
}
.CodeMirror-hint { font-size: 12pt; }

View file

@ -0,0 +1,232 @@
var project;
function Project(name, place, config, docs) {
this.name = name;
this.docs = Object.create(null);
this.tabs = place.appendChild(document.createElement("ul"));
this.tabs.className = "tabs";
var self = this;
CodeMirror.on(this.tabs, "click", function (e) {
var target = e.target || e.srcElement;
if (target.nodeName.toLowerCase() != "li") return;
var doc = self.findDoc(target.textContent);
if (doc) self.selectDoc(doc);
});
var myConf = {
switchToDoc: function (name) {
self.selectDoc(self.findDoc(name));
},
useWorker: false
};
for (var prop in config) myConf[prop] = config[prop];
var server = this.server = new CodeMirror.TernServer(myConf);
var firstDoc;
for (name in docs) {
var data = this.registerDoc(name, new CodeMirror.Doc(docs[name], "javascript"));
if (!firstDoc) firstDoc = data;
}
this.curDoc = firstDoc;
this.setSelectedTab(firstDoc);
var keyMap = {
"Ctrl-I": function (cm) {
server.showType(cm);
},
"Ctrl-O": function (cm) {
server.showDocs(cm);
},
"Ctrl-Space": function (cm) {
server.complete(cm);
},
"Ctrl-J": function (cm) {
server.jumpToDef(cm);
},
"Ctrl-,": function (cm) {
server.jumpBack(cm);
},
"Ctrl-Q": function (cm) {
server.rename(cm);
}
};
this.editor = new CodeMirror(place, {
mode: 'text/javascript',
theme: "eclipse",
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets: true,
indentWithTabs: true,
indentUnit: 4,
tabSize: 4,
extraKeys: keyMap,
value: firstDoc.doc
});
this.editor.on("cursorActivity", function (cm) {
server.updateArgHints(cm);
});
}
Project.prototype = {
findDoc: function (name) {
return this.docs[name];
},
registerDoc: function (name, doc) {
this.server.addDoc(name, doc);
var data = this.docs[name] = {
name: name,
doc: doc,
tab: this.tabs.appendChild(document.createElement("li"))
};
data.tab.textContent = name;
return data;
},
unregisterDoc: function (doc) {
this.server.delDoc(doc.name);
delete this.docs[doc.name];
this.tabs.removeChild(doc.tab);
if (this.curDoc == doc)
for (var n in this.docs) return this.selectDoc(this.docs[n]);
},
setSelectedTab: function (doc) {
for (var n = this.tabs.firstChild; n; n = n.nextSibling)
n.className = n.textContent == doc.name ? "selected" : "";
},
selectDoc: function (doc) {
if (doc == this.curDoc) return;
this.server.hideDoc(this.curDoc);
this.setSelectedTab(doc);
this.curDoc = doc;
this.editor.swapDoc(doc.doc);
}
};
// Initialization
CodeMirror.on(window, "load", function () {
var cmds = document.getElementById("commands");
CodeMirror.on(cmds, "change", function () {
if (!project || cmds.selectedIndex === 0) return;
var found = commands[cmds.value];
cmds.selectedIndex = 0;
project.editor.focus();
if (found) found();
});
var projects = document.getElementById("projects");
var projectNames = [];
var projectTags = document.querySelectorAll("project");
for (var i = 0; i < projectTags.length; i++) {
var opt = projects.appendChild(document.createElement("option"));
projectNames.push(opt.textContent = projectTags[i].id);
}
CodeMirror.on(projects, "change", function () {
initProject(projects.value, function () {
projects.selectedIndex = 0;
project.editor.focus();
});
});
function updateFromHash() {
var name = location.hash.slice(1);
if (projectNames.indexOf(name) > -1 &&
(!project || project.name != name)) {
initProject(name);
return true;
}
}
CodeMirror.on(window, "hashchange", updateFromHash);
updateFromHash() || initProject("simple");
});
function loadFiles(project, c) {
var found = {};
function inner(node) {
while (node && node.nodeName != "PRE") node = node.nextSibling;
if (!node) return c(found);
if (node.hasAttribute("file")) {
load(node.getAttribute("file"), function (data) {
found[node.id] = data;
inner(node.nextSibling);
});
} else {
found[node.id] = node.textContent;
inner(node.nextSibling);
}
}
inner(project.firstChild);
}
function words(str) {
return str ? str.split(" ") : [];
}
function initProject(name, c) {
var node = document.getElementById(name);
var plugins = {};
words(node.getAttribute("data-plugins")).forEach(function (name) {
plugins[name] = true;
});
if (plugins.requirejs) plugins.requirejs = {
override: {
"jquery": "=$"
}
};
loadFiles(node, function (files) {
var place = document.getElementById("place");
place.textContent = "";
if (project) project.server.destroy();
project = new Project(name, place, {
defs: [ecma5],
plugins: plugins
}, files);
location.hash = "#" + name;
c && c();
});
}
var commands = {
complete: function () {
project.server.complete(project.editor);
},
jumptodef: function () {
project.server.jumpToDef(project.editor);
},
finddocs: function () {
project.server.showDocs(project.editor);
},
findtype: function () {
project.server.showType(project.editor);
},
rename: function () {
project.server.rename(project.editor);
},
addfile: function () {
var name = prompt("Name of the new buffer", "");
if (name == null) return;
if (!name) name = "test";
var i = 0;
while (project.findDoc(name + (i || ""))) ++i;
project.selectDoc(project.registerDoc(name + (i || ""), new CodeMirror.Doc("", "javascript")));
},
delfile: function () {
var hasDoc = false;
for (var _ in project.docs) {
hasDoc = true;
break;
}
if (hasDoc) project.unregisterDoc(project.curDoc);
}
};

View file

@ -0,0 +1,142 @@
@font-face {
font-family: 'Signika';
font-style: normal;
font-weight: 700;
src: local('Signika-Bold'), url(http://themes.googleusercontent.com/static/fonts/signika/v3/7M5kxD4eGxuhgFaIk95pBRsxEYwM7FgeyaSgU71cLG0.woff) format('woff');
}
@font-face {
font-family: 'Ubuntu Mono';
font-style: normal;
font-weight: 500;
src: local('Ubuntu Mono'), local('UbuntuMono-Regular'), url('http://themes.googleusercontent.com/static/fonts/ubuntumono/v3/ViZhet7Ak-LRXZMXzuAfkYbN6UDyHWBl620a-IRfuBk.woff') format('woff');
}
body {
font-family: "Helvetica Neue", "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, sans-serif;
color: #222;
font-size: 11pt;
max-width: 700px;
margin: 0 0 0 60px;
padding: 60px 0 4em;
}
#top {
position: fixed;
top: 0;
background: white;
padding-top: 15px;
left: 20px; right: 20px;
z-index: 5;
}
#head {
border-radius: 5px;
background: #1c5b64;
box-shadow: 0px 3px 3px rgba(0, 0, 0, .5);
position: relative;
font-family: "Signika", sans-serif;
font-weight: 700;
}
#head > a {
border-right: 1px solid #276c81;
display: inline-block;
height: 25px;
padding: 5px 20px;
color: white;
text-decoration: none;
line-height: 25px;
font-size: 17px;
}
#head > a.title {
font-size: 20px;
line-height: 24px;
padding-left: 80px;
background: url(logo.png);
background-position: 40px center;
background-size: auto 80%;
background-repeat: no-repeat;
border-bottom-left-radius: 5px;
border-top-left-radius: 5px;
}
#head > a:hover {
background-color: #276c81 !important;
}
.title span {
font-size: 13px;
}
code, pre { font-family: "Ubuntu Mono", monospace; }
code { color: #124f55; font-size: 110%; }
pre {
border-left: 3px solid #def;
padding: 2px 0 2px 10px;
}
h1, h2, h3, h4 {
font-family: "Signika", sans-serif;
font-weight: 700;
color: #124f55;
}
h1 { font-size: 20pt; }
h2 { font-size: 17pt; }
h3 { font-size: 13pt; }
h4 { font-size: 11pt; }
a, a:visited, a code { color: #df4c11; text-decoration: none; }
a:hover { text-decoration: underline; }
ul, ol {
margin: 0;
padding: 0;
}
li {
margin-left: 1.5em;
padding: 0;
}
li p { margin: 0; }
dd p:first-child { margin-top: 1px; }
dd { margin-left: 20px; }
dt { text-indent: -1em; padding-left: 1em; }
a[id] {
position: relative;
display: inline-block;
vertical-align: top;
top: -60px;
}
.release-note {
margin-left: 1em;
}
/* CodeMirror default theme for highlighting */
.cm-s-default .cm-keyword {color: #708;}
.cm-s-default .cm-atom {color: #219;}
.cm-s-default .cm-number {color: #164;}
.cm-s-default .cm-def {color: #00f;}
.cm-s-default .cm-variable {color: black;}
.cm-s-default .cm-variable-2 {color: #05a;}
.cm-s-default .cm-variable-3 {color: #085;}
.cm-s-default .cm-property {color: black;}
.cm-s-default .cm-operator {color: black;}
.cm-s-default .cm-comment {color: #a50;}
.cm-s-default .cm-string {color: #a11;}
.cm-s-default .cm-string-2 {color: #f50;}
.cm-s-default .cm-meta {color: #555;}
.cm-s-default .cm-error {color: #f00;}
.cm-s-default .cm-qualifier {color: #555;}
.cm-s-default .cm-builtin {color: #30a;}
.cm-s-default .cm-bracket {color: #997;}
.cm-s-default .cm-tag {color: #170;}
.cm-s-default .cm-attribute {color: #00c;}
.cm-s-default .cm-header {color: blue;}
.cm-s-default .cm-quote {color: #090;}
.cm-s-default .cm-hr {color: #999;}
.cm-s-default .cm-link {color: #00c;}

View file

@ -1,102 +1,254 @@
<!doctype html> <!doctype html>
<html> <html>
<head>
<meta charset="utf-8">
<title>QML Tern Demo</title>
<!-- CodeMirror --> <head>
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css"> <meta charset="utf-8">
<script src="../node_modules/codemirror/lib/codemirror.js"></script> <title>Tern QML Demo</title>
<link rel="stylesheet" href="../node_modules/codemirror/theme/eclipse.css">
<script src="../node_modules/codemirror/addon/hint/show-hint.js"></script>
<script src="../node_modules/codemirror/addon/edit/closetag.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
<script src="../node_modules/codemirror/addon/selection/active-line.js"></script>
<script src="../node_modules/codemirror/mode/javascript/javascript.js"></script>
<!-- Acorn --> <!-- CodeMirror Stylesheets -->
<script src="../node_modules/acorn/dist/acorn.js"></script> <link rel=stylesheet href="../node_modules/codemirror/lib/codemirror.css">
<script src="../node_modules/acorn/dist/acorn_loose.js"></script> <link rel="stylesheet" href="../node_modules/codemirror/theme/eclipse.css">
<script src="../node_modules/acorn/dist/walk.js"></script> <link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css">
<script src="../node_modules/acorn-qml/inject.js"></script>
<script src="../node_modules/acorn-qml/index.js"></script>
<script src="../node_modules/acorn-qml/loose/inject.js"></script>
<script src="../node_modules/acorn-qml/loose/index.js"></script>
<script src="../node_modules/acorn-qml/walk/index.js"></script>
<!-- Tern JS --> <!-- CodeMirror-JavaScript Stylesheets -->
<script src="../node_modules/tern/lib/signal.js"></script> <link rel="stylesheet" href="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.css">
<script src="../node_modules/tern/lib/tern.js"></script>
<script src="../node_modules/tern/lib/def.js"></script>
<script src="../node_modules/tern/lib/comment.js"></script>
<script src="../node_modules/tern/lib/infer.js"></script>
<script src="../qml.js"></script>
<!-- Official CodeMirror Tern addon --> <!-- CodeMirror-Extension Stylesheets -->
<script src="../node_modules/codemirror/addon/tern/tern.js"></script> <link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hover/text-hover.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/templates-hint.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-hint-eclipse.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-context-info.css">
<!-- Extension of CodeMirror Tern addon --> <!-- Demo Specific Stylesheets -->
<link rel="stylesheet" href="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.css"> <link rel=stylesheet href="./docs.css">
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-extension.js"></script> <link rel=stylesheet href="./demo.css">
<script src="defs/ecma5.json.js"></script> </head>
<!-- CodeMirror Extension --> <body>
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-hint-eclipse.css"> <h1>Demo with QML Tern plugin </h1>
<script src="../node_modules/codemirror-extension/addon/hint/show-context-info.js"></script> <title>QML Tern Demo</title>
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/show-context-info.css">
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hint/templates-hint.css"> <!-- CodeMirror -->
<script src="../node_modules/codemirror-extension/addon/hint/templates-hint.js"></script> <script src="../node_modules/codemirror/lib/codemirror.js"></script>
<script src="../node_modules/codemirror/addon/hint/show-hint.js"></script>
<script src="../node_modules/codemirror/addon/edit/closetag.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/codemirror/addon/edit/matchbrackets.js"></script>
<script src="../node_modules/codemirror/addon/selection/active-line.js"></script>
<script src="../node_modules/codemirror/mode/javascript/javascript.js"></script>
<!-- CodeMirror Javascript --> <!-- Acorn -->
<script src="../node_modules/codemirror-javascript/addon/hint/javascript/javascript-templates.js"></script> <script src="../node_modules/acorn/dist/acorn.js"></script>
<script src="../node_modules/acorn/dist/acorn_loose.js"></script>
<script src="../node_modules/acorn/dist/walk.js"></script>
<script src="../node_modules/acorn-qml/inject.js"></script>
<script src="../node_modules/acorn-qml/index.js"></script>
<script src="../node_modules/acorn-qml/loose/inject.js"></script>
<script src="../node_modules/acorn-qml/loose/index.js"></script>
<script src="../node_modules/acorn-qml/walk/index.js"></script>
<!-- Tern Hover --> <!-- Tern JS -->
<link rel="stylesheet" href="../node_modules/codemirror-extension/addon/hover/text-hover.css"> <script src="../node_modules/tern/lib/signal.js"></script>
<script src="../node_modules/codemirror-extension/addon/hover/text-hover.js"></script> <script src="../node_modules/tern/lib/tern.js"></script>
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-hover.js"></script> <script src="../node_modules/tern/lib/def.js"></script>
</head> <script src="../node_modules/tern/lib/comment.js"></script>
<body> <script src="../node_modules/tern/lib/infer.js"></script>
<h1>Demo with QML Tern plugin </h1> <script src="../qml.js"></script>
<div style="border: solid 1px #AAAAAA;">
<form><textarea id="code" name="code">import QtQuick 2.3&#10;Window {&#10;&#09;prop: {&#10;&#09;&#09;Qt.quit();&#10;&#09;}&#10;}&#10;</textarea></form> <!-- Official CodeMirror Tern addon -->
<script src="../node_modules/codemirror/addon/tern/tern.js"></script>
<!-- ECMA 5th Edition Definitions File -->
<script src="defs/ecma5.json.js"></script>
<!-- CodeMirror Extension -->
<script src="../node_modules/codemirror-extension/addon/hint/show-context-info.js"></script>
<script src="../node_modules/codemirror-extension/addon/hint/templates-hint.js"></script>
<!-- CodeMirror Javascript -->
<script src="../node_modules/codemirror-javascript/addon/hint/javascript/javascript-templates.js"></script>
<!-- Tern Hover -->
<script src="../node_modules/codemirror-extension/addon/hover/text-hover.js"></script>
<script src="../node_modules/codemirror-javascript/addon/hint/tern/tern-hover.js"></script>
<!-- Extra script to control project logic -->
<script src="./demo.js"></script>
<div style="position: relative" id="demospace">
<div id="menus">
<select id="commands">
<option>commands...</option>
<option value="complete">Autocomplete (Ctrl-Space)</option>
<option value="jumptodef">Jump to definition (ctrl-J)</option>
<option value="finddocs">Describe (Ctrl-O)</option>
<option value="findtype">Find type of (Ctrl-I)</option>
<option value="rename">Rename variable (Ctrl-Q)</option>
<option value="addfile">Add a new file</option>
<option value="delfile">Remove this file</option>
</select>
</div> </div>
<script type="text/javascript"> <form id="place">
function passAndHint(cm) { <ul class="tabs">
setTimeout(function() {cm.execCommand("autocomplete");}, 100); <li class="selected">test</li>
return CodeMirror.Pass; </ul>
} <div class="CodeMirror cm-s-default">
<div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 5px; left: 40px;">
<textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea>
</div>
<div class="CodeMirror-vscrollbar" cm-not-content="true" style="display: block; bottom: 0px;">
<div style="min-width: 1px; height: 580px;"></div>
</div>
<div class="CodeMirror-hscrollbar" cm-not-content="true">
<div style="height: 100%; min-height: 1px; width: 0px;"></div>
</div>
<div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div>
<div class="CodeMirror-gutter-filler" cm-not-content="true"></div>
<div class="CodeMirror-scroll" tabindex="-1">
<div class="CodeMirror-sizer" style="margin-left: 30px; margin-bottom: -21px; border-right-width: 9px; min-height: 580px; min-width: 531.891px; padding-right: 21px; padding-bottom: 0px;">
<div style="position: relative; top: 0px;">
<div class="CodeMirror-lines">
<div style="position: relative; outline: none;">
<div class="CodeMirror-measure"><span><span></span>x</span>
</div>
<div class="CodeMirror-measure"></div>
<div style="position: relative; z-index: 1;"></div>
<div class="CodeMirror-cursors">
<div class="CodeMirror-cursor" style="left: 9px; top: 0px; height: 22px;">&nbsp;</div>
</div>
<div class="CodeMirror-code">
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">1</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Use ctrl-space to complete something</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">2</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">co</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">3</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">document</span>.<span class="cm-property">body</span>.<span class="cm-property">a</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">4</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">5</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Put the cursor in or after an expression, press ctrl-i to</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">6</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// find its type</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">7</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">8</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">foo</span> <span class="cm-operator">=</span> [<span class="cm-string">"array"</span>, <span class="cm-string">"of"</span>, <span class="cm-string">"strings"</span>]</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">9</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">bar</span> <span class="cm-operator">=</span> <span class="cm-variable">foo</span>.<span class="cm-property">slice</span>(<span class="cm-number">0</span>, <span class="cm-number">2</span>).<span class="cm-property">join</span>(<span class="cm-string">""</span>).<span class="cm-property">split</span>(<span class="cm-string">"a"</span>)[<span class="cm-number">0</span>]</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">10</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">11</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// Works for locally defined types too.</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">12</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">13</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">function</span> <span class="cm-def">CTor</span>() { <span class="cm-keyword">this</span>.<span class="cm-property">size</span> <span class="cm-operator">=</span> <span class="cm-number">10</span> }</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">14</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">CTor</span>.<span class="cm-property">prototype</span>.<span class="cm-property">hallo</span> <span class="cm-operator">=</span> <span class="cm-string">"hallo"</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">15</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">16</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-keyword">var</span> <span class="cm-def">baz</span> <span class="cm-operator">=</span> <span class="cm-keyword">new</span> <span class="cm-variable">CTor</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">17</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-variable">baz</span>.</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">18</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">19</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// You can press ctrl-q when the cursor is on a variable</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">20</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// name to rename it. Try it with CTor...</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">21</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">22</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// When the cursor is in an argument list, the arguments</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">23</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span class="cm-comment">// are shown below the editor.</span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">24</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">25</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;">[<span class="cm-number">1</span>].<span class="cm-property">reduce</span>( )</span></pre></div>
<div style="position: relative;">
<div class="CodeMirror-gutter-wrapper" style="left: -30px;">
<div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 21px;">26</div>
</div><pre class=" CodeMirror-line "><span style="padding-right: 0.1px;"><span cm-text=""></span></span></pre></div>
</div>
</div>
</div>
</div>
</div>
<div style="position: absolute; height: 9px; width: 1px; top: 580px;"></div>
<div class="CodeMirror-gutters" style="height: 589px;">
<div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 29px;"></div>
</div>
</div>
</div>
</form>
</div>
function myHint(cm) { <div style="display: none" id="projects">
return CodeMirror.showHint(cm, CodeMirror.ternHint, {async: true}); <project id="simple" data-plugins="qml">
} <pre id="main.qml">MyButton {
}
</pre>
<pre id="MyButton.qml">Button {
property int width;
property int height;
property var parent;
}
</pre>
</project>
</div>
</body>
CodeMirror.commands.autocomplete = function(cm) { </html>
CodeMirror.showHint(cm, myHint);
}
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
mode: 'text/javascript',
theme : "eclipse",
styleActiveLine: true,
lineNumbers: true,
lineWrapping: true,
autoCloseBrackets: true,
matchBrackets: true,
indentWithTabs: true,
indentUnit: 4,
extraKeys: {
"'.'": passAndHint,
"Ctrl-Space": "autocomplete",
"Ctrl-I": function(cm) { CodeMirror.tern.showType(cm); },
"Ctrl-J": function(cm) { CodeMirror.tern.jumpToDef(cm); },
"Alt-,": function(cm) { CodeMirror.tern.jumpBack(cm); },
"Ctrl-Q": function(cm) { CodeMirror.tern.rename(cm); }
},
gutters: ["CodeMirror-linenumbers"],
ternWith: { plugins: { "qml" : true } }
});
</script>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -24,8 +24,8 @@ var groupName;
function TestCase(group, code, run) { function TestCase(group, code, run) {
this.code = code; this.code = code;
this.group = group; this.group = group;
this.runTest = run || function (server, callback) { this.runTest = run || function (server, callback, code) {
callback("fail", code, "runTest function was not provided."); callback("fail", this.code, "runTest function was not provided.");
}; };
} }
@ -37,19 +37,19 @@ exports.isolate = function (code) {
i--; i--;
} }
} }
} };
exports.groupStart = function (group) { exports.groupStart = function (group) {
groupName = group; groupName = group;
} };
exports.groupEnd = function () { exports.groupEnd = function () {
groupName = undefined; groupName = undefined;
} };
exports.test = function (code, runTest) { exports.test = function (code, runTest) {
testCases.push(new TestCase(groupName || "Default", code, runTest)); testCases.push(new TestCase(groupName || "Default", code, runTest));
} };
exports.testCompletion = function (code, expected, beforeTest) { exports.testCompletion = function (code, expected, beforeTest) {
testCases.push(new TestCase(groupName || "Default", code, function (server, callback) { testCases.push(new TestCase(groupName || "Default", code, function (server, callback) {
@ -70,7 +70,7 @@ exports.testCompletion = function (code, expected, beforeTest) {
} }
}); });
}, beforeTest)); }, beforeTest));
} };
exports.testDefinition = function (code, expected, beforeTest) { exports.testDefinition = function (code, expected, beforeTest) {
testCases.push(new TestCase(groupName || "Default", code, function (server, callback) { testCases.push(new TestCase(groupName || "Default", code, function (server, callback) {
@ -91,21 +91,21 @@ exports.testDefinition = function (code, expected, beforeTest) {
} }
}); });
}, beforeTest)); }, beforeTest));
} };
exports.runTests = function (config, callback) { exports.runTests = function (config, callback) {
for (var i = 0; i < testCases.length; ++i) { for (var i = 0; i < testCases.length; ++i) {
var test = testCases[i]; var test = testCases[i];
if (test.group === config.group) { if (test.group === config.group) {
var server = createServer(); var server = createServer();
test.runTest(server, callback); test.runTest(server, callback, test.code);
} }
} }
}; };
function createServer(defs) { function createServer(defs) {
var plugins = {}; var plugins = {};
plugins["qml"] = {}; plugins.qml = true;
var server = new tern.Server({ var server = new tern.Server({
ecmaVersion: 5, ecmaVersion: 5,
plugins : plugins, plugins : plugins,
@ -114,12 +114,12 @@ function createServer(defs) {
return server; return server;
} }
function assertCompletion(server, code, expected, pos, callback) { var assertCompletion = exports.assertCompletion = function (server, code, expected, pos, callback) {
server.addFile("test1.qml", code); server.addFile("main.qml", code);
server.request({ server.request({
query : { query : {
type: "completions", type: "completions",
file: "test1.qml", file: "main.qml",
end: pos, end: pos,
types: true, types: true,
docs: false, docs: false,
@ -139,12 +139,12 @@ function assertCompletion(server, code, expected, pos, callback) {
}); });
}; };
function assertDefinition(server, code, expected, pos, callback) { var assertDefinition = exports.assertDefinition = function (server, code, expected, pos, callback) {
server.addFile("test1.qml", code); server.addFile("main.qml", code);
server.request({ server.request({
query : { query : {
type: "definition", type: "definition",
file: "test1.qml", file: "main.qml",
end: pos, end: pos,
types: true, types: true,
docs: false, docs: false,
@ -175,6 +175,7 @@ function addPath(str, pt) {
} }
var misMatch = exports.misMatch = function (exp, act) { var misMatch = exports.misMatch = function (exp, act) {
var mis = null;
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) { if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act); if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
} else if (exp instanceof RegExp || act instanceof RegExp) { } else if (exp instanceof RegExp || act instanceof RegExp) {
@ -184,12 +185,12 @@ var misMatch = exports.misMatch = function (exp, act) {
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act); if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length; if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
for (var i = 0; i < act.length; ++i) { for (var i = 0; i < act.length; ++i) {
var mis = misMatch(exp[i], act[i]); mis = misMatch(exp[i], act[i]);
if (mis) return addPath(mis, i); if (mis) return addPath(mis, i);
} }
} else { } else {
for (var prop in exp) { for (var prop in exp) {
var mis = misMatch(exp[prop], act[prop]); mis = misMatch(exp[prop], act[prop]);
if (mis) return addPath(mis, prop); if (mis) return addPath(mis, prop);
} }
} }

View file

@ -8,6 +8,8 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use strict";
module.exports = { module.exports = {
"!name": "ecma5", "!name": "ecma5",
"!define": { "!define": {
@ -975,4 +977,4 @@ module.exports = {
"!url": "https://developer.mozilla.org/en-US/docs/JSON", "!url": "https://developer.mozilla.org/en-US/docs/JSON",
"!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference." "!doc": "JSON (JavaScript Object Notation) is a data-interchange format. It closely resembles a subset of JavaScript syntax, although it is not a strict subset. (See JSON in the JavaScript Reference for full details.) It is useful when writing any kind of JavaScript-based application, including websites and browser extensions. For example, you might store user information in JSON format in a cookie, or you might store extension preferences in JSON in a string-valued browser preference."
} }
} };

View file

@ -8,7 +8,7 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
var driver = require("./driver.js"); var driver = require("./driver.js");
@ -20,7 +20,7 @@ function group(name) {
function groupEnd() { function groupEnd() {
if (typeof console === "object" && console.groupEnd) { if (typeof console === "object" && console.groupEnd) {
console.groupEnd(name); console.groupEnd();
} }
} }
@ -29,8 +29,9 @@ function log(title, message) {
} }
var stats, tests = []; var stats, tests = [];
tests.push(require("./test-completions.js")); tests.push(require("./test-scoping.js"));
tests.push(require("./test-finddef.js")); tests.push(require("./test-finddef.js"));
tests.push(require("./test-completions.js"));
function report(state, code, message) { function report(state, code, message) {
if (state != "ok") {++stats.failed; log(code, message);} if (state != "ok") {++stats.failed; log(code, message);}
@ -45,9 +46,9 @@ for (var i = 0; i < tests.length; i++) {
stats = test.stats = {testsRun: 0, failed: 0}; stats = test.stats = {testsRun: 0, failed: 0};
var config = test.config || {}; var config = test.config || {};
config.group = test.group; config.group = test.group;
var t0 = +new Date; var t0 = +new Date();
driver.runTests(config, report); driver.runTests(config, report);
test.stats.duration = +new Date - t0; test.stats.duration = +new Date() - t0;
groupEnd(); groupEnd();
} }

View file

@ -8,58 +8,259 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
var driver = require("./driver.js"); var driver = require("./driver.js");
var test = driver.test; var test = driver.test;
var testCompletion = driver.testCompletion; var testCompletion = driver.testCompletion;
var assertCompletion = driver.assertCompletion;
var groupStart = driver.groupStart; var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd; var groupEnd = driver.groupEnd;
var group = exports.group = "Code Completion" var group = exports.group = "Code Completion";
groupStart(group); groupStart(group);
// Import Completions // Local Directory Completions
//testCompletion("import QtQu|", { testCompletion('My|', {
// start: { line: 0, ch: 7 }, start: { line: 0, ch: 0 },
// end: { line: 0, ch: 11 }, end: { line: 0, ch: 2 },
// isProperty: false, isProperty: false,
// isObjectKey: false, isObjectKey: false,
// completions: [{ name: "QtQuick", type: "", origin: "QML" }] completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
//}); }, function (server) {
// server.addFile("MyObject.qml", "Button {}");
//testCompletion("import QtQuick 2.|", { });
// start: { line: 0, ch: 17 },
// end: { line: 0, ch: 17 }, testCompletion('import "./subdir/"\nSameDirTest {\n\t|\n}', {
// isProperty: false, start: { line: 2, ch: 1 },
// isObjectKey: false, end: { line: 2, ch: 1 },
// completions: [ isProperty: false,
// { name: "0", type: "number", origin: "QML" }, isObjectKey: false,
// { name: "1", type: "number", origin: "QML" }, completions: [
// { name: "2", type: "number", origin: "QML" }, { name: "obj", type: "?", origin: "subdir/Button.qml" },
// { name: "3", type: "number", origin: "QML" }, { name: "Button", type: "Button", origin: "subdir/Button.qml" },
// { name: "4", type: "number", origin: "QML" }, { name: "SameDirTest", type: "SameDirTest", origin: "subdir/SameDirTest.qml" }
// { name: "5", type: "number", origin: "QML" } ]
// ] }, function (server) {
//}); server.addFile("subdir/SameDirTest.qml", "Button {}");
// server.addFile("subdir/Button.qml", "QtObject {property var obj}");
//testCompletion('import "other.qml" as Other\n|', { });
// start: { line: 1, ch: 0 },
// end: { line: 1, ch: 0 }, testCompletion('MyObject {\n\t|\n}', {
// isProperty: false, start: { line: 1, ch: 1 },
// isObjectKey: false, end: { line: 1, ch: 1 },
// completions: [{ name: "Other", type: "?", origin: "test1.qml" }] isProperty: false,
//}) isObjectKey: false,
// completions: [
//testCompletion('My|', { { name: "width", type: "number", origin: "MyObject.qml" },
// start: { line: 0, ch: 2 }, { name: "MyObject", type: "MyObject", origin: "MyObject.qml" }
// end: { line: 0, ch: 2 }, ]
// isProperty: false, }, function (server) {
// isObjectKey: false, server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}");
// completions: [{ name: "MyObject", type: "Button", origin: "MyObject.qml" }] });
//}, function (server) {
// server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}"); testCompletion('MyObject {\n\tid: obj\n\ts: obj.|\n}', {
//}); start: { line: 2, ch: 8 },
end: { line: 2, ch: 8 },
isProperty: true,
isObjectKey: false,
completions: [{ name: "width", type: "number", origin: "MyObject.qml" }]
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tproperty int width\n}");
});
testCompletion('Button {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "Button.qml" },
{ name: "Button", type: "Button", origin: "Button.qml" }
]
}, function (server) {
server.addFile("Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('CButton {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "height", type: "number", origin: "Button.qml" },
{ name: "numClicks", type: "number", origin: "CButton.qml" },
{ name: "text", type: "string", origin: "Button.qml" },
{ name: "width", type: "number", origin: "Button.qml" },
{ name: "Button", type: "Button", origin: "Button.qml" },
{ name: "CButton", type: "CButton", origin: "CButton.qml" }
]
}, function (server) {
server.addFile("CButton.qml", "Button {\n\tproperty int numClicks\n}");
server.addFile("Button.qml", "QtObject {\n\tproperty string text\n\tproperty int width\n\tproperty int height\n}");
});
testCompletion('CButton {\n\tid:btn\n\ts: btn.|\n}', {
start: { line: 2, ch: 8 },
end: { line: 2, ch: 8 },
isProperty: true,
isObjectKey: false,
completions: [
{ name: "height", type: "number", origin: "Button.qml" },
{ name: "numClicks", type: "number", origin: "CButton.qml" },
{ name: "text", type: "string", origin: "Button.qml" },
{ name: "width", type: "number", origin: "Button.qml" }
]
}, function (server) {
server.addFile("CButton.qml", "Button {\n\tproperty int numClicks\n}");
server.addFile("Button.qml", "QtObject {\n\tproperty string text\n\tproperty int width\n\tproperty int height\n}");
});
// Directory Import Completions
testCompletion('NotVisible {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: []
}, function (server) {
server.addFile("subdir/NotVisible.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/"\nButton {\n\t|\n}', {
start: { line: 2, ch: 1 },
end: { line: 2, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "subdir/Button.qml" },
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.Button {\n\t|\n}', {
start: { line: 2, ch: 1 },
end: { line: 2, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "onClicked", type: "Signal Handler", origin: "subdir/Button.qml" },
{ name: "Controls", type: "Controls", origin: "main.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.|', {
start: { line: 1, ch: 9 },
end: { line: 1, ch: 9 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls.|.', {
start: { line: 1, ch: 9 },
end: { line: 1, ch: 9 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "Button", type: "Button", origin: "subdir/Button.qml" }
]
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
testCompletion('import "./subdir/" as Controls\nControls..|', {
start: { line: 1, ch: 10 },
end: { line: 1, ch: 10 },
isProperty: false,
isObjectKey: false,
completions: []
}, function (server) {
server.addFile("subdir/Button.qml", "QtObject {\n\signal clicked(int mouseX, int mouseY)\n}");
});
test("{Add File After Import}", function (server, callback, name) {
var failed;
assertCompletion(server, "", {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 0 },
isProperty: false,
isObjectKey: false,
completions: []
}, 0, function (mis) {
failed = mis;
});
if (failed) {
return callback("fail", name, "- failed on initial file " + failed);
}
server.addFile("MyObject.qml", "QtObject {\n\tproperty var test\n}");
assertCompletion(server, "M", {
start: { line: 0, ch: 0 },
end: { line: 0, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [{ name: "MyObject", type: "MyObject", origin: "MyObject.qml" }]
}, 1, function (mis) {
failed = mis;
});
if (failed) {
return callback("fail", name, "- failed after adding file " + failed);
}
return callback("ok", name);
});
// Cyclic Dependency Completions
testCompletion('Cyclic {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test", type: "?", origin: "Cyclic.qml" },
{ name: "Cyclic", type: "Cyclic", origin: "Cyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic.qml", "Cyclic {\n\property var test\n}");
});
testCompletion('Cyclic2 {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test1", type: "?", origin: "Cyclic2.qml" },
{ name: "test2", type: "?", origin: "OtherCyclic.qml" },
{ name: "Cyclic2", type: "Cyclic2", origin: "Cyclic2.qml" },
{ name: "OtherCyclic", type: "OtherCyclic", origin: "OtherCyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic2.qml", "OtherCyclic {\n\property var test1\n}");
server.addFile("OtherCyclic.qml", "Cyclic2 {\n\property var test2\n}");
});
testCompletion('OtherCyclic {\n\t|\n}', {
start: { line: 1, ch: 1 },
end: { line: 1, ch: 1 },
isProperty: false,
isObjectKey: false,
completions: [
{ name: "test2", type: "?", origin: "OtherCyclic.qml" },
{ name: "Cyclic", type: "Cyclic", origin: "Cyclic.qml" },
{ name: "OtherCyclic", type: "OtherCyclic", origin: "OtherCyclic.qml" }
]
}, function (server) {
server.addFile("Cyclic.qml", "OtherCyclic {\n\property var test1\n}");
server.addFile("OtherCyclic.qml", "Cyclic {\n\property var test2\n}");
});
// QML Object Property Completions // QML Object Property Completions
testCompletion("Window {\n\tproperty int height\n\the|\n}", { testCompletion("Window {\n\tproperty int height\n\the|\n}", {
@ -67,7 +268,7 @@ testCompletion("Window {\n\tproperty int height\n\the|\n}", {
end: { line: 2, ch: 3 }, end: { line: 2, ch: 3 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }] completions: [{ name: "height", type: "number", origin: "main.qml" }]
}); });
testCompletion("Window {\n\tproperty int height\n\tproperty int width\n\tproperty string text\n\t|\n}", { testCompletion("Window {\n\tproperty int height\n\tproperty int width\n\tproperty string text\n\t|\n}", {
@ -76,9 +277,9 @@ testCompletion("Window {\n\tproperty int height\n\tproperty int width\n\tpropert
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "height", type: "number", origin: "test1.qml" }, { name: "height", type: "number", origin: "main.qml" },
{ name: "text", type: "string", origin: "test1.qml" }, { name: "text", type: "string", origin: "main.qml" },
{ name: "width", type: "number", origin: "test1.qml" } { name: "width", type: "number", origin: "main.qml" }
] ]
}); });
@ -96,8 +297,8 @@ testCompletion("Window {\n\tproperty var prop\n\tfunction test() {\n\t\t|\n\t}\n
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "prop", type: "?", origin: "test1.qml" }, { name: "prop", type: "?", origin: "main.qml" },
{ name: "test", type: "fn()", origin: "test1.qml" } { name: "test", type: "fn()", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -115,7 +316,7 @@ testCompletion("Window {\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\
end: { line: 5, ch: 11 }, end: { line: 5, ch: 11 },
isProperty: true, isProperty: true,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }] completions: [{ name: "height", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: btn.|\n}", { testCompletion("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: btn.|\n}", {
@ -123,7 +324,7 @@ testCompletion("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tprope
end: { line: 6, ch: 11 }, end: { line: 6, ch: 11 },
isProperty: true, isProperty: true,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "height", type: "number", origin: "test1.qml" }] completions: [{ name: "height", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t}\n\ts: bt|\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t}\n\ts: bt|\n}", {
@ -131,7 +332,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t}\n\ts
end: { line: 5, ch: 6 }, end: { line: 5, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "btn", type: "Button", origin: "test1.qml" }] completions: [{ name: "btn", type: "Button", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -139,7 +340,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\tid: btn\n\t\ts: i
end: { line: 4, ch: 6 }, end: { line: 4, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "?", origin: "test1.qml" }] completions: [{ name: "id", type: "?", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\tid: btn\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -147,7 +348,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\tid: btn\n\t\t
end: { line: 4, ch: 6 }, end: { line: 4, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "number", origin: "test1.qml" }] completions: [{ name: "id", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\tid: btn\n\t\ts: i|\n\t}\n}", {
@ -155,7 +356,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\tid: btn\n\t\ts
end: { line: 4, ch: 6 }, end: { line: 4, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "string", origin: "test1.qml" }] completions: [{ name: "id", type: "string", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\ts: i|\n\t}\n}", {
@ -163,7 +364,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id\n\t\ts: i|\n\t}\n}", {
end: { line: 3, ch: 6 }, end: { line: 3, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "?", origin: "test1.qml" }] completions: [{ name: "id", type: "?", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\ts: i|\n\t}\n}", {
@ -171,7 +372,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty var id: 34\n\t\ts: i|\n\t}\n}
end: { line: 3, ch: 6 }, end: { line: 3, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "number", origin: "test1.qml" }] completions: [{ name: "id", type: "number", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\ts: i|\n\t}\n}", { testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\ts: i|\n\t}\n}", {
@ -179,7 +380,7 @@ testCompletion("Window {\n\tButton {\n\t\tproperty string id\n\t\ts: i|\n\t}\n}"
end: { line: 3, ch: 6 }, end: { line: 3, ch: 6 },
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [{ name: "id", type: "string", origin: "test1.qml" }] completions: [{ name: "id", type: "string", origin: "main.qml" }]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
testCompletion("Window {\n\tid: wind\n\tfunction test() {\n\t\t|\n\t}\n}", { testCompletion("Window {\n\tid: wind\n\tfunction test() {\n\t\t|\n\t}\n}", {
@ -188,8 +389,8 @@ testCompletion("Window {\n\tid: wind\n\tfunction test() {\n\t\t|\n\t}\n}", {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "test", type: "fn()", origin: "test1.qml" }, { name: "test", type: "fn()", origin: "main.qml" },
{ name: "wind", type: "Window", origin: "test1.qml" } { name: "wind", type: "Window", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -209,7 +410,7 @@ testCompletion("Window {\n\tproperty var test: |\n}", {
{ name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" }, { name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" },
{ name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" }, { name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" },
{ name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" }, { name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" },
{ name: "test", type: "?", origin: "test1.qml" }, { name: "test", type: "?", origin: "main.qml" },
{ name: "undefined", type: "?", origin: "ecma5" }, { name: "undefined", type: "?", origin: "ecma5" },
{ name: "Array", type: "fn(size: number)", origin: "ecma5" }, { name: "Array", type: "fn(size: number)", origin: "ecma5" },
{ name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" }, { name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" },
@ -324,7 +525,7 @@ testCompletion("Window {\n\tfunction test() {\n\t\t|\n\t}\n}", {
{ name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" }, { name: "isNaN", type: "fn(value: number) -> bool", origin: "ecma5" },
{ name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" }, { name: "parseFloat", type: "fn(string: string) -> number", origin: "ecma5" },
{ name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" }, { name: "parseInt", type: "fn(string: string, radix?: number) -> number", origin: "ecma5" },
{ name: "test", type: "fn()", origin: "test1.qml" }, { name: "test", type: "fn()", origin: "main.qml" },
{ name: "undefined", type: "?", origin: "ecma5" }, { name: "undefined", type: "?", origin: "ecma5" },
{ name: "Array", type: "fn(size: number)", origin: "ecma5" }, { name: "Array", type: "fn(size: number)", origin: "ecma5" },
{ name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" }, { name: "Boolean", type: "fn(value: ?) -> bool", origin: "ecma5" },
@ -355,7 +556,7 @@ testCompletion("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\t|\n}", {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "onClicked", type: "Signal Handler", origin: "test1.qml" } { name: "onClicked", type: "Signal Handler", origin: "main.qml" }
] ]
}); });
@ -373,8 +574,8 @@ testCompletion("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\ts: |\n}",
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "clicked", type: "fn(mouseX: number, mouseY: number)", origin: "test1.qml" }, { name: "clicked", type: "fn(mouseX: number, mouseY: number)", origin: "main.qml" },
{ name: "onClicked", type: "Signal Handler", origin: "test1.qml" } { name: "onClicked", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -384,8 +585,8 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\ts: |\n}",
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" }, { name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" } { name: "onError", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -395,8 +596,8 @@ testCompletion("Window {\n\tid: wind\n\tsignal error(string msg, boolean flag)\n
isProperty: true, isProperty: true,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" }, { name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" } { name: "onError", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -406,10 +607,10 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\tonError: |
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" }, { name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" }, { name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "test1.qml" }, { name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" } { name: "onError", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -419,10 +620,10 @@ testCompletion("Window {\n\tsignal error(string msg, boolean flag)\n\tonError: {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" }, { name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" }, { name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "test1.qml" }, { name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" } { name: "onError", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -432,10 +633,10 @@ testCompletion("Window {\n\tproperty int msg\n\tsignal error(string msg, boolean
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "error", type: "fn(msg: string, flag: bool)", origin: "test1.qml" }, { name: "error", type: "fn(msg: string, flag: bool)", origin: "main.qml" },
{ name: "flag", type: "bool", origin: "test1.qml" }, { name: "flag", type: "bool", origin: "main.qml" },
{ name: "msg", type: "string", origin: "test1.qml" }, { name: "msg", type: "string", origin: "main.qml" },
{ name: "onError", type: "Signal Handler", origin: "test1.qml" } { name: "onError", type: "Signal Handler", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -454,10 +655,10 @@ testCompletion("Window {\n\tfunction test(a, b, c) {\n\t\t|\n\t}\n}", {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "a", type: "?", origin: "test1.qml" }, { name: "a", type: "?", origin: "main.qml" },
{ name: "b", type: "?", origin: "test1.qml" }, { name: "b", type: "?", origin: "main.qml" },
{ name: "c", type: "?", origin: "test1.qml" }, { name: "c", type: "?", origin: "main.qml" },
{ name: "test", type: "fn(a: ?, b: ?, c: ?)", origin: "test1.qml" } { name: "test", type: "fn(a: ?, b: ?, c: ?)", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -467,8 +668,8 @@ testCompletion("Window {\n\tfunction test(a) {\n\t\ta = 3\n\t\t|\n\t}\n}", {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "a", type: "number", origin: "test1.qml" }, { name: "a", type: "number", origin: "main.qml" },
{ name: "test", type: "fn(a: number)", origin: "test1.qml" } { name: "test", type: "fn(a: number)", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -478,8 +679,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\ttest("something")\n\t\t|\n\t
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "a", type: "string", origin: "test1.qml" }, { name: "a", type: "string", origin: "main.qml" },
{ name: "test", type: "fn(a: string)", origin: "test1.qml" } { name: "test", type: "fn(a: string)", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -489,8 +690,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\t|\n\t\treturn 7\n\t}\n}', {
isProperty: false, isProperty: false,
isObjectKey: false, isObjectKey: false,
completions: [ completions: [
{ name: "a", type: "?", origin: "test1.qml" }, { name: "a", type: "?", origin: "main.qml" },
{ name: "test", type: "fn(a: ?) -> number", origin: "test1.qml" } { name: "test", type: "fn(a: ?) -> number", origin: "main.qml" }
] ]
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
@ -502,8 +703,8 @@ testCompletion('Window {\n\tfunction test(a) {\n\t\t|\n\t\treturn 7\n\t}\n}', {
// isProperty: false, // isProperty: false,
// isObjectKey: false, // isObjectKey: false,
// completions: [ // completions: [
// { name: "a", type: "?", origin: "test1.qml" }, // { name: "a", type: "?", origin: "main.qml" },
// { name: "test", type: "fn()", origin: "test1.qml" } // { name: "test", type: "fn()", origin: "main.qml" }
// ] // ]
//}, function (server) { server.jsDefs = []; }); //}, function (server) { server.jsDefs = []; });

View file

@ -8,79 +8,163 @@
* Contributors: * Contributors:
* QNX Software Systems - Initial API and implementation * QNX Software Systems - Initial API and implementation
*******************************************************************************/ *******************************************************************************/
"use-strict"; "use strict";
var driver = require("./driver.js"); var driver = require("./driver.js");
var test = driver.test;
var testDefinition = driver.testDefinition; var testDefinition = driver.testDefinition;
var assertDefinition = driver.assertDefintion;
var groupStart = driver.groupStart; var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd; var groupEnd = driver.groupEnd;
var group = exports.group = "Find Definition"; var group = exports.group = "Find Definition";
groupStart(group); groupStart(group);
// Directory Imports
// TODO: Getting this test to pass breaks some of the type inferencing which is more important
//testDefinition('My|Object {}', {
// origin: "MyObject.qml",
// start: { line: 0, ch: 0 },
// end: { line: 0, ch: 6 },
// file: "MyObject.qml",
// contextOffset: 0
//}, function (server) {
// server.addFile("MyObject.qml", "Button {}");
//});
testDefinition("MyObject {\n\tte|stProp: ident\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 14 },
end: { line: 1, ch: 22 },
file: "MyObject.qml",
contextOffset: 23
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tproperty var testProp\n}");
});
testDefinition("MyObject {\n\ts: te|stSig()\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "MyObject.qml",
contextOffset: 17
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig()\n}");
});
testDefinition("MyObject {\n\tonTe|stSig: ident\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 },
file: "MyObject.qml",
contextOffset: 17
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig()\n}");
});
testDefinition("MyObject {\n\tonTestSig: ar|g0\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 20 },
end: { line: 1, ch: 24 },
file: "MyObject.qml",
contextOffset: 29
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tsignal testSig(int arg0)\n}");
});
testDefinition("MyObject {\n\ts: te|stFn()\n}", {
origin: "MyObject.qml",
start: { line: 1, ch: 10 },
end: { line: 1, ch: 16 },
file: "MyObject.qml",
contextOffset: 19
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tfunction testFn() {}\n}");
});
testDefinition("MyObject {\n\ts: btn|Id\n}", {
origin: undefined,
start: undefined,
end: undefined,
file: undefined,
contextOffset: undefined
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tid: btnId\n}");
});
testDefinition("MyObject {\n\tot|her: ident\n}", {
origin: undefined,
start: undefined,
end: undefined,
file: undefined,
contextOffset: undefined
}, function (server) {
server.addFile("MyObject.qml", "Button {\n\tSecondButton {\n\t\tjproperty var other\n\t}\n}");
});
// ID Property // ID Property
testDefinition("QtObject {\n\tid: obj\n\tproperty var prop: {\n\t\tob|j\n\t}\n}", { testDefinition("QtObject {\n\tid: obj\n\tproperty var prop: {\n\t\tob|j\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 5 }, start: { line: 1, ch: 5 },
end: { line: 1, ch: 8 }, end: { line: 1, ch: 8 },
file: "test1.qml", file: "main.qml",
contextOffset: 16 contextOffset: 16
}); });
testDefinition("Window {\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", { testDefinition("Window {\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 2, ch: 6 }, start: { line: 2, ch: 6 },
end: { line: 2, ch: 9 }, end: { line: 2, ch: 9 },
file: "test1.qml", file: "main.qml",
contextOffset: 25 contextOffset: 25
}); });
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", { testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: btn\n\t\tproperty int height\n\t}\n\ttest: bt|n\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 3, ch: 6 }, start: { line: 3, ch: 6 },
end: { line: 3, ch: 9 }, end: { line: 3, ch: 9 },
file: "test1.qml", file: "main.qml",
contextOffset: 43 contextOffset: 43
}); });
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: bt|n\n\t\tproperty int height\n\t}\n}", { testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tid: bt|n\n\t\tproperty int height\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 3, ch: 6 }, start: { line: 3, ch: 6 },
end: { line: 3, ch: 9 }, end: { line: 3, ch: 9 },
file: "test1.qml", file: "main.qml",
contextOffset: 43 contextOffset: 43
}); });
// Property Declarations // Property Declarations
testDefinition("QtObject {\n\tproperty var prop\n\tpr|op: 3\n}", { testDefinition("QtObject {\n\tproperty var prop\n\tpr|op: 3\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 14 }, start: { line: 1, ch: 14 },
end: { line: 1, ch: 18 }, end: { line: 1, ch: 18 },
file: "test1.qml", file: "main.qml",
contextOffset: 25 contextOffset: 25
}); });
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tprop: b|tn\n\t}\n}", { testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tprop: b|tn\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 14 }, start: { line: 1, ch: 14 },
end: { line: 1, ch: 17 }, end: { line: 1, ch: 17 },
file: "test1.qml", file: "main.qml",
contextOffset: 23 contextOffset: 23
}); });
testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tButton {\n\t\t\tprop: b|tn\n\t\t}\n\t}\n}", { testDefinition("Window {\n\tproperty var btn\n\tButton {\n\t\tButton {\n\t\t\tprop: b|tn\n\t\t}\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 14 }, start: { line: 1, ch: 14 },
end: { line: 1, ch: 17 }, end: { line: 1, ch: 17 },
file: "test1.qml", file: "main.qml",
contextOffset: 23 contextOffset: 23
}); });
testDefinition("Window {\n\tButton {\n\t\tproperty var btn\n\t\tbt|n: 3\n\t}\n}", { testDefinition("Window {\n\tButton {\n\t\tproperty var btn\n\t\tbt|n: 3\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 2, ch: 15 }, start: { line: 2, ch: 15 },
end: { line: 2, ch: 18 }, end: { line: 2, ch: 18 },
file: "test1.qml", file: "main.qml",
contextOffset: 34 contextOffset: 34
}); });
@ -94,115 +178,115 @@ testDefinition("Window {\n\tButton {\n\t\tproperty var btn\n\t\tButton {\n\t\t\t
// Signals and Signal Handlers // Signals and Signal Handlers
testDefinition("Window {\n\tsignal clic|ked(int mouseX, int mouseY)\n}", { testDefinition("Window {\n\tsignal clic|ked(int mouseX, int mouseY)\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonCli|cked: 3\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonCli|cked: 3\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: mou|seX\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: mou|seX\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 20 }, start: { line: 1, ch: 20 },
end: { line: 1, ch: 26 }, end: { line: 1, ch: 26 },
file: "test1.qml", file: "main.qml",
contextOffset: 29 contextOffset: 29
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: cli|cked(3,4)\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: cli|cked(3,4)\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: onCli|cked\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tonClicked: onCli|cked\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.onCli|cked\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.onCli|cked\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.cli|cked(3,4)\n}", { testDefinition("Window {\n\tsignal clicked(int mouseX, int mouseY)\n\tid: wind\n\tonClicked: wind.cli|cked(3,4)\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 8 }, start: { line: 1, ch: 8 },
end: { line: 1, ch: 15 }, end: { line: 1, ch: 15 },
file: "test1.qml", file: "main.qml",
contextOffset: 17 contextOffset: 17
}); });
testDefinition("Window {\n\tproperty int msg\n\tsignal error(string msg, boolean flag)\n\tonError: {\n\t\tms|g\n\t}\n}", { testDefinition("Window {\n\tproperty int msg\n\tsignal error(string msg, boolean flag)\n\tonError: {\n\t\tms|g\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 2, ch: 21 }, start: { line: 2, ch: 21 },
end: { line: 2, ch: 24 }, end: { line: 2, ch: 24 },
file: "test1.qml", file: "main.qml",
contextOffset: 48 contextOffset: 48
}, function (server) { server.jsDefs = []; }); }, function (server) { server.jsDefs = []; });
// Function Declarations // Function Declarations
testDefinition("Window {\n\tfunction te|st(a) {}\n}", { testDefinition("Window {\n\tfunction te|st(a) {}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 10 }, start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 }, end: { line: 1, ch: 14 },
file: "test1.qml", file: "main.qml",
contextOffset: 19 contextOffset: 19
}); });
testDefinition("Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}", { testDefinition("Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 15 }, start: { line: 1, ch: 15 },
end: { line: 1, ch: 16 }, end: { line: 1, ch: 16 },
file: "test1.qml", file: "main.qml",
contextOffset: 24 contextOffset: 24
}); });
testDefinition("Window {\n\tfunction test(a) {\n\t\tte|st(3)\n\t}\n}", { testDefinition("Window {\n\tfunction test(a) {\n\t\tte|st(3)\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 10 }, start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 }, end: { line: 1, ch: 14 },
file: "test1.qml", file: "main.qml",
contextOffset: 19 contextOffset: 19
}); });
testDefinition("Window {\n\tfunction test(a) {}\n\ts: te|st(3)\n}", { testDefinition("Window {\n\tfunction test(a) {}\n\ts: te|st(3)\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 10 }, start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 }, end: { line: 1, ch: 14 },
file: "test1.qml", file: "main.qml",
contextOffset: 19 contextOffset: 19
}); });
testDefinition("Window {\n\tfunction test(a) {}\n\ts: {\n\t\tte|st(3)\n\t}\n}", { testDefinition("Window {\n\tfunction test(a) {}\n\ts: {\n\t\tte|st(3)\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 10 }, start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 }, end: { line: 1, ch: 14 },
file: "test1.qml", file: "main.qml",
contextOffset: 19 contextOffset: 19
}); });
testDefinition("Window {\n\tfunction test(a) {}\n\tid: wind\n\ts: {\n\t\twind.te|st(3)\n\t}\n}", { testDefinition("Window {\n\tfunction test(a) {}\n\tid: wind\n\ts: {\n\t\twind.te|st(3)\n\t}\n}", {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 10 }, start: { line: 1, ch: 10 },
end: { line: 1, ch: 14 }, end: { line: 1, ch: 14 },
file: "test1.qml", file: "main.qml",
contextOffset: 19 contextOffset: 19
}); });
@ -215,10 +299,10 @@ testDefinition("Window {\n\tfunction test(a) {}\n\tte|st: 3;\n}", {
}); });
testDefinition('Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}\n\tproperty int a', { testDefinition('Window {\n\tfunction test(a) {\n\t\ta|\n\t}\n}\n\tproperty int a', {
origin: "test1.qml", origin: "main.qml",
start: { line: 1, ch: 15 }, start: { line: 1, ch: 15 },
end: { line: 1, ch: 16 }, end: { line: 1, ch: 16 },
file: "test1.qml", file: "main.qml",
contextOffset: 24 contextOffset: 24
}); });

View file

@ -0,0 +1,409 @@
/*******************************************************************************
* Copyright (c) 2015 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*******************************************************************************/
"use strict";
var plugin = require("../qml.js");
var infer = require("tern/lib/infer");
var driver = require("./driver.js");
var test = driver.test;
var groupStart = driver.groupStart;
var groupEnd = driver.groupEnd;
var group = exports.group = "Custom Scoping";
groupStart(group);
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("QMLObjScope::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 scope = new plugin.QMLObjScope(fileScope, null, obj);
// Define a property on the Obj Type
obj.defProp("first", 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");
}
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);
});
});
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::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 objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// 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, "- QMLMemScope 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()", 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);
});
});
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::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 objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// 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);
});
});
test("QMLMemScope::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 objScope = new plugin.QMLObjScope(fileScope, null, obj);
var scope = new plugin.QMLMemScope(objScope, null, fileScope);
// 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("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);
});
});
groupEnd();