Daniel Werner has uploaded a new change for review.
https://gerrit.wikimedia.org/r/50185
Change subject: Gives names to all important constructors for improved
debugging experience
......................................................................
Gives names to all important constructors for improved debugging experience
Change-Id: I3f15c65b3225eba12fd51d0ad814c1630e1ee2e7
---
M DataTypes/resources/dataTypes.js
M DataValues/resources/DataValue.js
M DataValues/resources/dataValues.js
M DataValues/resources/dataValues.util.js
M DataValues/resources/values/BoolValue.js
M DataValues/resources/values/MonolingualTextValue.js
M DataValues/resources/values/MultilingualTextValue.js
M DataValues/resources/values/NumberValue.js
M DataValues/resources/values/StringValue.js
M DataValues/resources/values/UnknownValue.js
M DataValues/tests/qunit/dataValues.util.inherit.tests.js
M ValueParsers/resources/Api.js
M ValueParsers/resources/ApiBasedValueParser.js
M ValueParsers/resources/ValueParser.js
M ValueParsers/resources/ValueParserFactory.js
15 files changed, 114 insertions(+), 39 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/DataValues
refs/changes/85/50185/1
diff --git a/DataTypes/resources/dataTypes.js b/DataTypes/resources/dataTypes.js
index e0a4958..28d772a 100644
--- a/DataTypes/resources/dataTypes.js
+++ b/DataTypes/resources/dataTypes.js
@@ -15,7 +15,7 @@
* @since 0.1
* @type Object
*/
-var dataTypes = new ( function( $, mw, undefined ) {
+var dataTypes = new ( function Dt( $, mw ) {
'use strict';
// TODO: the whole structure of this is a little weird, perhaps there
should be a
@@ -37,7 +37,7 @@
* @param {Object} formatter
* @param {Object} validators
*/
- dt.DataType = function( typeId, dataValueType, parser, formatter,
validators ) {
+ dt.DataType = function DtDataType( typeId, dataValueType, parser,
formatter, validators ) {
if( dataValueType === undefined ) {
throw new Error( 'All arguments must be provided for
creating a new DataType object' );
}
diff --git a/DataValues/resources/DataValue.js
b/DataValues/resources/DataValue.js
index 7c42a50..164d3a7 100644
--- a/DataValues/resources/DataValue.js
+++ b/DataValues/resources/DataValue.js
@@ -15,7 +15,7 @@
* @abstract
* @since 0.1
*/
-dv.DataValue = function() {};
+dv.DataValue = function DvDataValue() {};
dv.DataValue.prototype = {
/**
diff --git a/DataValues/resources/dataValues.js
b/DataValues/resources/dataValues.js
index 6422367..6886a22 100644
--- a/DataValues/resources/dataValues.js
+++ b/DataValues/resources/dataValues.js
@@ -14,7 +14,7 @@
* @since 0.1
* @type Object
*/
-var dataValues = new( function( $, undefined ) {
+var dataValues = new( function Dv( $ ) {
'use strict';
var dvs = [];
diff --git a/DataValues/resources/dataValues.util.js
b/DataValues/resources/dataValues.util.js
index 8788167..d0f47c7 100644
--- a/DataValues/resources/dataValues.util.js
+++ b/DataValues/resources/dataValues.util.js
@@ -2,9 +2,9 @@
* @file
* @ingroup DataValues
* @licence GNU GPL v2+
- * @author Daniel Werner
+ * @author Daniel Werner < [email protected] >
*/
-( function( $, dv ) {
+( function ( $, dv ) {
'use strict';
/**
@@ -18,16 +18,25 @@
* Helper for prototypical inheritance.
* @since 0.1
*
- * @param {Function} base Constructor which will be used for the
prototype chain.
+ * @param {string} name (optional) The name of the new constructor.
This is handy for debugging
+ * purposes since instances of the constructor might be
displayed under that name.
+ * @param {Function} base Constructor which will be used for the
prototype chain. This function
+ * will not be the constructor returned by the function but will
be called by it.
* @param {Function} [constructor] for overwriting base constructor.
Can be omitted.
* @param {Object} [members] properties overwriting or extending those
of the base.
* @return Function Constructor of the new, extended type.
+ *
+ * @throws {Error} In case a malicious function name is given or a
reserved word is used
*/
- dv.util.inherit = function( base, constructor, members ) {
- // allow to omit constructor since it can be inherited
directly. But if given, require it as
- // second parameter for readability. If no constructor, second
parameter is the prototype
- // extension object.
- if( members === undefined ) {
+ dv.util.inherit = function( name, base, constructor, members ) {
+ // the name is optional
+ if( typeof name !== 'string' ) {
+ members = constructor; constructor = base; base = name;
name = false;
+ }
+
+ // allow to omit constructor since it can be inherited
directly. But if given, require it as second parameter
+ // for readability. If no constructor, second parameter is the
prototype extension object.
+ if( !members ) {
if( $.isFunction( constructor ) ) {
members = {};
} else {
@@ -35,7 +44,22 @@
constructor = false;
}
}
- var NewConstructor = constructor || function() { base.apply(
this, arguments ); };
+ // if no name is given, find suitable constructor's name
+ name = name || constructor.name || ( base.name ? base.name +
'_SubProto' : 'SomeInherited' );
+ // make sure name is just a function name and not some
executable JavaScript
+ name = name.replace( /(?:(^\d+)|[^\w$])/ig, '' );
+
+ if( !name ) { // only bad characters were in the name!
+ throw new Error( 'Bad constructor name given. Only word
characters and $ are allowed.' );
+ }
+
+ // function we execute in our real constructor created by evil
eval:
+ var evilsSeed = constructor || base,
+ NewConstructor;
+
+ // for creating a named function with a variable name, there is
just no other way...
+ eval( 'NewConstructor = function ' + name +
+ '(){ evilsSeed.apply( this, arguments ); }' );
var NewPrototype = function(){}; // new constructor for
avoiding base constructor and with it any side-effects
NewPrototype.prototype = base.prototype;
diff --git a/DataValues/resources/values/BoolValue.js
b/DataValues/resources/values/BoolValue.js
index 1af21b9..462a325 100644
--- a/DataValues/resources/values/BoolValue.js
+++ b/DataValues/resources/values/BoolValue.js
@@ -24,7 +24,7 @@
*
* @param {String} value
*/
-dv.BoolValue = dv.util.inherit( PARENT, constructor, {
+dv.BoolValue = dv.util.inherit( 'DvBoolValue', PARENT, constructor, {
/**
* @see dv.DataValue.getSortKey
diff --git a/DataValues/resources/values/MonolingualTextValue.js
b/DataValues/resources/values/MonolingualTextValue.js
index cf60fec..36a1e4a 100644
--- a/DataValues/resources/values/MonolingualTextValue.js
+++ b/DataValues/resources/values/MonolingualTextValue.js
@@ -5,7 +5,7 @@
* @author Daniel Werner
* @author Jeroen De Dauw < [email protected] >
*/
-( function( dv, $, undefined ) {
+( function( dv, $ ) {
'use strict';
var PARENT = dv.DataValue,
@@ -26,7 +26,7 @@
* @param {String} languageCode
* @param {String} value
*/
-dv.MonolingualTextValue = dv.util.inherit( PARENT, constructor, {
+dv.MonolingualTextValue = dv.util.inherit( 'DvMonolingualTextValue', PARENT,
constructor, {
/**
* @see dv.DataValue.getSortKey
diff --git a/DataValues/resources/values/MultilingualTextValue.js
b/DataValues/resources/values/MultilingualTextValue.js
index 631967b..f062018 100644
--- a/DataValues/resources/values/MultilingualTextValue.js
+++ b/DataValues/resources/values/MultilingualTextValue.js
@@ -5,7 +5,7 @@
* @author Jeroen De Dauw < [email protected] >
* @author Daniel Werner
*/
-( function( dv, $, undefined ) {
+( function( dv, $ ) {
'use strict';
var PARENT = dv.DataValue,
@@ -24,7 +24,7 @@
*
* @param {dv.MonolingualTextValue[]} monoLingualValues
*/
-dv.MultilingualTextValue = dv.util.inherit( PARENT, constructor, {
+dv.MultilingualTextValue = dv.util.inherit( 'DvMultilingualTextValue', PARENT,
constructor, {
/**
* @see dv.DataValue.getSortKey
diff --git a/DataValues/resources/values/NumberValue.js
b/DataValues/resources/values/NumberValue.js
index b04a2ed..b0071df 100644
--- a/DataValues/resources/values/NumberValue.js
+++ b/DataValues/resources/values/NumberValue.js
@@ -6,7 +6,7 @@
*
* @author Daniel Werner < [email protected] >
*/
-( function( dv, $, undefined ) {
+( function( dv, $ ) {
'use strict';
var PARENT = dv.DataValue,
@@ -24,7 +24,7 @@
*
* @param {Number} value
*/
- dv.NumberValue = dv.util.inherit( PARENT, constructor, {
+ dv.NumberValue = dv.util.inherit( 'DvNumberValue', PARENT, constructor,
{
/**
* @see dv.DataValue.getSortKey
*
diff --git a/DataValues/resources/values/StringValue.js
b/DataValues/resources/values/StringValue.js
index 4eac002..d7e094c 100644
--- a/DataValues/resources/values/StringValue.js
+++ b/DataValues/resources/values/StringValue.js
@@ -7,7 +7,7 @@
* @author Daniel Werner
* @author Jeroen De Dauw < [email protected] >
*/
-( function( dv, $, undefined ) {
+( function( dv, $ ) {
'use strict';
var PARENT = dv.DataValue,
@@ -25,7 +25,7 @@
*
* @param {String} value
*/
-dv.StringValue = dv.util.inherit( PARENT, constructor, {
+dv.StringValue = dv.util.inherit( 'StringValue', PARENT, constructor, {
/**
* @see dv.DataValue.getSortKey
diff --git a/DataValues/resources/values/UnknownValue.js
b/DataValues/resources/values/UnknownValue.js
index 433e7da..ad2c308 100644
--- a/DataValues/resources/values/UnknownValue.js
+++ b/DataValues/resources/values/UnknownValue.js
@@ -24,7 +24,7 @@
*
* @param {String} value
*/
- dv.UnknownValue = dv.util.inherit( PARENT, constructor, {
+ dv.UnknownValue = dv.util.inherit( 'DvUnknownValue', PARENT,
constructor, {
/**
* @see dv.DataValue.getSortKey
diff --git a/DataValues/tests/qunit/dataValues.util.inherit.tests.js
b/DataValues/tests/qunit/dataValues.util.inherit.tests.js
index d09b35f..a301bdd 100644
--- a/DataValues/tests/qunit/dataValues.util.inherit.tests.js
+++ b/DataValues/tests/qunit/dataValues.util.inherit.tests.js
@@ -8,7 +8,7 @@
* @licence GNU GPL v2+
* @author Daniel Werner
*/
-( function( dv, $, QUnit, undefined ) {
+( function( dv, $, QUnit ) {
'use strict';
QUnit.module( 'dataValues.util.inherit', QUnit.newMwEnvironment() );
@@ -35,7 +35,13 @@
else if( constructor === null ) {
// constructor omitted, check for right param mapping:
C = dv.util.inherit( base, members );
- var C2 = dv.util.inherit( base,
C.prototype.constructor, members );
+ var C2 = dv.util.inherit( base,
C.prototype.constructor, members ),
+ origConstructorOfC = C.prototype.constructor;
+
+ // constructors will never be the same since a new
function will be created in inherit(),
+ // so we have to set them to the same to test for all
the other prototype members.
+ C.prototype.constructor = null;
+ C2.prototype.constructor = null;
QUnit.assert.deepEqual(
C.prototype,
@@ -43,6 +49,7 @@
'inherit() works as expected if "constructor"
parameter was omitted.'
);
C2 = null;
+ C.prototype.constructor = origConstructorOfC;
}
else if( members === null ) {
C = dv.util.inherit( base, constructor );
@@ -60,14 +67,6 @@
( new C() ) instanceof base && ( new C() ) instanceof C,
'"instanceof" is working like it should'
);
-
- if( constructor !== null ) {
- QUnit.assert.equal(
- C,
- constructor,
- 'prototypes constructor property is set to
given constructor'
- );
- }
var proto = $.extend( {}, C.prototype );
if( members === null || !members.hasOwnProperty( 'constructor'
) ) {
@@ -89,7 +88,7 @@
foo: 'baa'
},
- inheritConstructor = function() {
+ inheritConstructor = function InheritTestConstructor() {
this.foo = 'test';
},
@@ -120,9 +119,20 @@
var C1 = inheritTest( Object, inheritConstructor, null );
inheritConstructorTest( C1 );
+ QUnit.assert.equal(
+ C1.name,
+ inheritConstructor.name,
+ 'Constructor returned by inherit() takes name of given
constructor function'
+ );
+
// inherit from C2:
var C2 = inheritTest( C1, null, inheritMembers );
inheritConstructorTest( C2 );
+
+ QUnit.assert.ok(
+ C2.name.indexOf( inheritConstructor.name ) === 0,
+ 'Constructor returned by inherit() uses name of given
constructor plus suffix'
+ );
} );
QUnit.test( 'inherit( base, constructor, members )', function( assert )
{
@@ -131,4 +141,45 @@
inheritConstructorTest( C );
} );
+ QUnit.test( 'inherit( name, ... ) with different names', function(
assert ) {
+ var names = [
+ [ '$' ],
+ [ '_' ],
+ [ '$foo' ],
+ [ '_foo' ],
+ [ 'foo' ],
+ [ 'foo42' ],
+ [ '42foo', 'foo' ],
+ [ 'function()xxx(){};', 'functionxxx' ],
+ [ 'xyz;${]123', 'xyz$123' ],
+ [ ';a;1;$;b;_;', 'a1$b_' ],
+ [ '();', false ],
+ [ '42', false ], // can't start function name with
number
+ [ 'class', false ], // reserved word
+ [ 'function', false ] // reserved word
+ ];
+
+ $.each( names, function( i, definition ) {
+ var testName = definition[0],
+ expectedName = definition[1] || (
definition[1] === undefined ? testName : false );
+
+ if( !expectedName ) {
+ assert.throws(
+ function() {
+ dv.util.inherit( testName,
Object );
+ },
+ 'inherit( \'' + testName + '\', ... );
will throw and error because of malicious constructor name.'
+ );
+ } else {
+ assert.equal(
+ dv.util.inherit( testName, Object
).name,
+ expectedName,
+ 'inherit( \'' + testName + '\', ... );
will use "' + expectedName + '" as name.'
+ );
+
+ }
+
+ } );
+ } );
+
}( dataValues, jQuery, QUnit ) );
diff --git a/ValueParsers/resources/Api.js b/ValueParsers/resources/Api.js
index c7d459b..45f70b6 100644
--- a/ValueParsers/resources/Api.js
+++ b/ValueParsers/resources/Api.js
@@ -4,7 +4,7 @@
* @licence GNU GPL v2+
* @author Jeroen De Dauw < [email protected] >
*/
-( function( mw, vp, $, dv, undefined ) {
+( function( mw, vp, $, dv ) {
'use strict';
/**
diff --git a/ValueParsers/resources/ApiBasedValueParser.js
b/ValueParsers/resources/ApiBasedValueParser.js
index 1b5e64a..a82ba30 100644
--- a/ValueParsers/resources/ApiBasedValueParser.js
+++ b/ValueParsers/resources/ApiBasedValueParser.js
@@ -6,7 +6,7 @@
*
* @author Daniel Werner < [email protected] >
*/
-( function( vp, dv, $, undefined ) {
+( function( vp, dv, $ ) {
'use strict';
var PARENT = vp.ValueParser;
@@ -20,7 +20,7 @@
* @abstract
* @since 0.1
*/
- vp.ApiBasedValueParser = dv.util.inherit( PARENT, {
+ vp.ApiBasedValueParser = dv.util.inherit( 'VpApiBasedValueParser',
PARENT, {
/**
* The key of the related API parser.
* @type String
diff --git a/ValueParsers/resources/ValueParser.js
b/ValueParsers/resources/ValueParser.js
index 50efb4d..857e54b 100644
--- a/ValueParsers/resources/ValueParser.js
+++ b/ValueParsers/resources/ValueParser.js
@@ -16,7 +16,7 @@
*
* @param {Object} options
*/
- vp.ValueParser = function( options ) {
+ vp.ValueParser = function VpValueParser( options ) {
this._options = options || {};
};
diff --git a/ValueParsers/resources/ValueParserFactory.js
b/ValueParsers/resources/ValueParserFactory.js
index 55e844d..fd7e88e 100644
--- a/ValueParsers/resources/ValueParserFactory.js
+++ b/ValueParsers/resources/ValueParserFactory.js
@@ -14,7 +14,7 @@
*
* @param {Object} valueParsers
*/
- vp.ValueParserFactory = function( valueParsers ) {
+ vp.ValueParserFactory = function VpValueParserFactory( valueParsers ) {
this._parsers = {};
for ( var parserId in valueParsers ) {
--
To view, visit https://gerrit.wikimedia.org/r/50185
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3f15c65b3225eba12fd51d0ad814c1630e1ee2e7
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/DataValues
Gerrit-Branch: master
Gerrit-Owner: Daniel Werner <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits