Permalink
Browse files

Better support for super() and super.method()

  • Loading branch information...
1 parent 4a6e778 commit 35ebea4503a2943916a13a130f5cdaa1b383e7ab @Swatinem Swatinem committed Sep 2, 2012
Showing with 128 additions and 93 deletions.
  1. 0 bin/harmonizr
  2. +29 −23 demo/lib/harmonizr.js
  3. +29 −23 lib/harmonizr.js
  4. +29 −23 src/harmonizr.js
  5. +29 −23 test/lib/harmonizr.js
  6. +12 −1 test/test.js
View
0 bin/harmonizr 100644 → 100755
File mode changed.
View
52 demo/lib/harmonizr.js
@@ -288,33 +288,39 @@ function processClasses(modifier, options) {
'; return ' + name + ';})()' + (node.type === Syntax.ClassDeclaration ? ';' : ''));
methods.forEach(function(method) {
+ var supers = [];
+ // collect all `super` Identifiers of calls and `super.X` MemberExpressions
+ traverse(method, function(innerNode) {
+ if ((innerNode.type === Syntax.CallExpression &&
+ innerNode.callee.type === Syntax.Identifier &&
+ innerNode.callee.name === 'super') ||
+ (innerNode.type === Syntax.MemberExpression &&
+ innerNode.object.type === Syntax.Identifier &&
+ innerNode.object.name === 'super')) {
+ supers.push(innerNode);
+ }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
+ return false;
+ }*/
+ });
+ supers.reverse();
+ supers.forEach(function(superItem) {
+ if (superItem.type === Syntax.CallExpression) {
+ // super(X) -> X__super.bind(this)(X)
+ modifier.replace(superItem.callee.loc.start, superItem.callee.loc.end,
+ name + '__super.bind(this)');
+ } else {
+ // super.method -> X__prototype.method.bind(this)
+ modifier.insert(superItem.property.loc.end,
+ '.bind(this)');
+ modifier.replace(superItem.object.loc.start, superItem.object.loc.end,
+ name + '__prototype');
+ }
+ });
+
if (method.key.name === 'constructor') {
- // replace calls to `super(...)` with `X__super.call(this, ...)`
- var superCalls = [];
- traverse(method, function(innerNode) {
- if (innerNode.type === Syntax.CallExpression &&
- innerNode.callee.type === Syntax.Identifier &&
- innerNode.callee.name === 'super') {
- superCalls.push(innerNode);
- }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
- return false;
- }*/
- });
- superCalls.reverse();
- superCalls.forEach(function(call) {
- if (call['arguments'].length) {
- modifier.replace(call.loc.start, call['arguments'][0].loc.start,
- name + '__super.call(this, ');
- } else {
- modifier.replace(call.loc.start, call.loc.end,
- name + '__super.call(this)');
- }
- });
-
modifier.replace(method.key.loc.start, method.key.loc.end,
'function ' + name);
} else {
- // TODO: rewrite calls to `super.method(...)` to `X__proto.method.call(this, ...)`
modifier.replace(method.key.loc.start, method.key.loc.end,
name + '.prototype.' + method.key.name + ' = function');
}
View
52 lib/harmonizr.js
@@ -288,33 +288,39 @@ function processClasses(modifier, options) {
'; return ' + name + ';})()' + (node.type === Syntax.ClassDeclaration ? ';' : ''));
methods.forEach(function(method) {
+ var supers = [];
+ // collect all `super` Identifiers of calls and `super.X` MemberExpressions
+ traverse(method, function(innerNode) {
+ if ((innerNode.type === Syntax.CallExpression &&
+ innerNode.callee.type === Syntax.Identifier &&
+ innerNode.callee.name === 'super') ||
+ (innerNode.type === Syntax.MemberExpression &&
+ innerNode.object.type === Syntax.Identifier &&
+ innerNode.object.name === 'super')) {
+ supers.push(innerNode);
+ }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
+ return false;
+ }*/
+ });
+ supers.reverse();
+ supers.forEach(function(superItem) {
+ if (superItem.type === Syntax.CallExpression) {
+ // super(X) -> X__super.bind(this)(X)
+ modifier.replace(superItem.callee.loc.start, superItem.callee.loc.end,
+ name + '__super.bind(this)');
+ } else {
+ // super.method -> X__prototype.method.bind(this)
+ modifier.insert(superItem.property.loc.end,
+ '.bind(this)');
+ modifier.replace(superItem.object.loc.start, superItem.object.loc.end,
+ name + '__prototype');
+ }
+ });
+
if (method.key.name === 'constructor') {
- // replace calls to `super(...)` with `X__super.call(this, ...)`
- var superCalls = [];
- traverse(method, function(innerNode) {
- if (innerNode.type === Syntax.CallExpression &&
- innerNode.callee.type === Syntax.Identifier &&
- innerNode.callee.name === 'super') {
- superCalls.push(innerNode);
- }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
- return false;
- }*/
- });
- superCalls.reverse();
- superCalls.forEach(function(call) {
- if (call['arguments'].length) {
- modifier.replace(call.loc.start, call['arguments'][0].loc.start,
- name + '__super.call(this, ');
- } else {
- modifier.replace(call.loc.start, call.loc.end,
- name + '__super.call(this)');
- }
- });
-
modifier.replace(method.key.loc.start, method.key.loc.end,
'function ' + name);
} else {
- // TODO: rewrite calls to `super.method(...)` to `X__proto.method.call(this, ...)`
modifier.replace(method.key.loc.start, method.key.loc.end,
name + '.prototype.' + method.key.name + ' = function');
}
View
52 src/harmonizr.js
@@ -288,33 +288,39 @@ function processClasses(modifier, options) {
'; return ' + name + ';})()' + (node.type === Syntax.ClassDeclaration ? ';' : ''));
methods.forEach(method => {
+ var supers = [];
+ // collect all `super` Identifiers of calls and `super.X` MemberExpressions
+ traverse(method, innerNode => {
+ if ((innerNode.type === Syntax.CallExpression &&
+ innerNode.callee.type === Syntax.Identifier &&
+ innerNode.callee.name === 'super') ||
+ (innerNode.type === Syntax.MemberExpression &&
+ innerNode.object.type === Syntax.Identifier &&
+ innerNode.object.name === 'super')) {
+ supers.push(innerNode);
+ }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
+ return false;
+ }*/
+ });
+ supers.reverse();
+ supers.forEach(superItem => {
+ if (superItem.type === Syntax.CallExpression) {
+ // super(X) -> X__super.bind(this)(X)
+ modifier.replace(superItem.callee.loc.start, superItem.callee.loc.end,
+ name + '__super.bind(this)');
+ } else {
+ // super.method -> X__prototype.method.bind(this)
+ modifier.insert(superItem.property.loc.end,
+ '.bind(this)');
+ modifier.replace(superItem.object.loc.start, superItem.object.loc.end,
+ name + '__prototype');
+ }
+ });
+
if (method.key.name === 'constructor') {
- // replace calls to `super(...)` with `X__super.call(this, ...)`
- var superCalls = [];
- traverse(method, innerNode => {
- if (innerNode.type === Syntax.CallExpression &&
- innerNode.callee.type === Syntax.Identifier &&
- innerNode.callee.name === 'super') {
- superCalls.push(innerNode);
- }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
- return false;
- }*/
- });
- superCalls.reverse();
- superCalls.forEach(call => {
- if (call['arguments'].length) {
- modifier.replace(call.loc.start, call['arguments'][0].loc.start,
- name + '__super.call(this, ');
- } else {
- modifier.replace(call.loc.start, call.loc.end,
- name + '__super.call(this)');
- }
- });
-
modifier.replace(method.key.loc.start, method.key.loc.end,
'function ' + name);
} else {
- // TODO: rewrite calls to `super.method(...)` to `X__proto.method.call(this, ...)`
modifier.replace(method.key.loc.start, method.key.loc.end,
name + '.prototype.' + method.key.name + ' = function');
}
View
52 test/lib/harmonizr.js
@@ -288,33 +288,39 @@ function processClasses(modifier, options) {
'; return ' + name + ';})()' + (node.type === Syntax.ClassDeclaration ? ';' : ''));
methods.forEach(function(method) {
+ var supers = [];
+ // collect all `super` Identifiers of calls and `super.X` MemberExpressions
+ traverse(method, function(innerNode) {
+ if ((innerNode.type === Syntax.CallExpression &&
+ innerNode.callee.type === Syntax.Identifier &&
+ innerNode.callee.name === 'super') ||
+ (innerNode.type === Syntax.MemberExpression &&
+ innerNode.object.type === Syntax.Identifier &&
+ innerNode.object.name === 'super')) {
+ supers.push(innerNode);
+ }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
+ return false;
+ }*/
+ });
+ supers.reverse();
+ supers.forEach(function(superItem) {
+ if (superItem.type === Syntax.CallExpression) {
+ // super(X) -> X__super.bind(this)(X)
+ modifier.replace(superItem.callee.loc.start, superItem.callee.loc.end,
+ name + '__super.bind(this)');
+ } else {
+ // super.method -> X__prototype.method.bind(this)
+ modifier.insert(superItem.property.loc.end,
+ '.bind(this)');
+ modifier.replace(superItem.object.loc.start, superItem.object.loc.end,
+ name + '__prototype');
+ }
+ });
+
if (method.key.name === 'constructor') {
- // replace calls to `super(...)` with `X__super.call(this, ...)`
- var superCalls = [];
- traverse(method, function(innerNode) {
- if (innerNode.type === Syntax.CallExpression &&
- innerNode.callee.type === Syntax.Identifier &&
- innerNode.callee.name === 'super') {
- superCalls.push(innerNode);
- }/* FIXME: can classes be nested? else if (innerNode !== node && innerNode.type === Syntax.ClassDeclaration) {
- return false;
- }*/
- });
- superCalls.reverse();
- superCalls.forEach(function(call) {
- if (call['arguments'].length) {
- modifier.replace(call.loc.start, call['arguments'][0].loc.start,
- name + '__super.call(this, ');
- } else {
- modifier.replace(call.loc.start, call.loc.end,
- name + '__super.call(this)');
- }
- });
-
modifier.replace(method.key.loc.start, method.key.loc.end,
'function ' + name);
} else {
- // TODO: rewrite calls to `super.method(...)` to `X__proto.method.call(this, ...)`
modifier.replace(method.key.loc.start, method.key.loc.end,
name + '.prototype.' + method.key.name + ' = function');
}
View
13 test/test.js
@@ -457,7 +457,18 @@ describe('harmonizr', function() {
var expected = 'var A = (function () {var A__super = B;' +
'var A__prototype = (typeof A__super !== "function" ? A__super : A__super.prototype);' +
'A.prototype = Object.create(A__prototype); \n' +
- ' function A(a) { \n\nA__super.call(this); \n\nA__super.call(this, a); }\n; return A;})();';
+ ' function A(a) { A__super.bind(this)\n(\n); A__super.bind(this)\n (\na); }\n; return A;})();';
+ harmonize(src, expected);
+ });
+
+ it('supports calls to super.method()', function() {
+ var src = 'class A extends B {\n' +
+ ' constructor() { (\nsuper.method\n).call(); return super.method; }\n'+
+ '}';
+ var expected = 'var A = (function () {var A__super = B;' +
+ 'var A__prototype = (typeof A__super !== "function" ? A__super : A__super.prototype);' +
+ 'A.prototype = Object.create(A__prototype); \n' +
+ ' function A() { (\nA__prototype.method.bind(this)\n).call(); return A__prototype.method.bind(this); }\n; return A;})();';
harmonize(src, expected);
});

0 comments on commit 35ebea4

Please sign in to comment.