Skip to content

Commit

Permalink
Merge pull request #48 from adrianheine/anonymousDefaultExportClass
Browse files Browse the repository at this point in the history
Better support for anonymous classes
  • Loading branch information
Rich-Harris authored Nov 18, 2017
2 parents 3689ddd + 76859a7 commit 387fb5f
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 18 deletions.
41 changes: 27 additions & 14 deletions src/program/types/ClassDeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import deindent from '../../utils/deindent.js';

export default class ClassDeclaration extends Node {
initialise(transforms) {
this.name = this.id.name;
this.findScope(true).addDeclaration(this.id, 'class');
if (this.id) {
this.name = this.id.name;
this.findScope(true).addDeclaration(this.id, 'class');
} else {
this.name = this.findScope(true).createIdentifier("defaultExport");
}

super.initialise(transforms);
}
Expand All @@ -21,37 +25,46 @@ export default class ClassDeclaration extends Node {

// if this is an export default statement, we have to move the export to
// after the declaration, because `export default var Foo = ...` is illegal
const syntheticDefaultExport =
this.parent.type === 'ExportDefaultDeclaration'
? `\n\n${i0}export default ${this.id.name};`
: '';
const isExportDefaultDeclaration = this.parent.type === 'ExportDefaultDeclaration';

if (syntheticDefaultExport) code.remove(this.parent.start, this.start);
if (isExportDefaultDeclaration) {
code.remove(this.parent.start, this.start);
}

code.overwrite(this.start, this.id.start, 'var ');
let c = this.start
if (this.id) {
code.overwrite(c, this.id.start, 'var ');
c = this.id.end
} else {
code.prependLeft(c, `var ${this.name}`);
}

if (this.superClass) {
if (this.superClass.end === this.body.start) {
code.remove(this.id.end, this.superClass.start);
code.appendLeft(this.id.end, ` = (function (${superName}) {\n${i1}`);
code.remove(c, this.superClass.start);
code.appendLeft(c, ` = (function (${superName}) {\n${i1}`);
} else {
code.overwrite(this.id.end, this.superClass.start, ' = ');
code.overwrite(c, this.superClass.start, ' = ');
code.overwrite(
this.superClass.end,
this.body.start,
`(function (${superName}) {\n${i1}`
);
}
} else {
if (this.id.end === this.body.start) {
code.appendLeft(this.id.end, ' = ');
if (c === this.body.start) {
code.appendLeft(c, ' = ');
} else {
code.overwrite(this.id.end, this.body.start, ' = ');
code.overwrite(c, this.body.start, ' = ');
}
}

this.body.transpile(code, transforms, !!this.superClass, superName);

const syntheticDefaultExport =
isExportDefaultDeclaration
? `\n\n${i0}export default ${this.name};`
: '';
if (this.superClass) {
code.appendLeft(this.end, `\n\n${i1}return ${this.name};\n${i0}}(`);
code.move(this.superClass.start, this.superClass.end, this.end);
Expand Down
12 changes: 8 additions & 4 deletions src/program/types/ClassExpression.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import Node from '../Node.js';

export default class ClassExpression extends Node {
initialise(transforms) {
this.name = this.id
this.name = ( this.id
? this.id.name
: this.parent.type === 'VariableDeclarator'
? this.parent.id.name
: this.parent.type === 'AssignmentExpression'
? this.parent.left.name
: this.findScope(true).createIdentifier('anonymous');
: this.parent.type !== 'AssignmentExpression'
? null
: this.parent.left.type === 'Identifier'
? this.parent.left.name
: this.parent.left.type === 'MemberExpression'
? this.parent.left.property.name
: null ) || this.findScope(true).createIdentifier('anonymous');

super.initialise(transforms);
}
Expand Down
23 changes: 23 additions & 0 deletions test/samples/classes.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,29 @@ module.exports = [
}());`
},

{
description:
'transpiles an anonymous class expression that is assigned to a property',

input: `
const q = {};
q.a = class {
c () {}
};`,

output: `
var q = {};
q.a = (function () {
function a () {}
a.prototype.c = function c () {};
return a;
}());`
},

{
description: 'allows constructor to be in middle of body',

Expand Down
28 changes: 28 additions & 0 deletions test/samples/modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,33 @@ module.exports = [
options: { transforms: { modules: false } },
input: `import 'foo'; export { foo };`,
output: `import 'foo'; export { foo };`
},

{
description:
'Supports anonymous classes as default export',
options: { transforms: { modules: false } },
input: `
export default class {
constructor() {
foo()
}
a() {
bar()
}
}
`,
output: `
var defaultExport = function defaultExport() {
foo()
};
defaultExport.prototype.a = function a () {
bar()
};
export default defaultExport;
`
}
];

0 comments on commit 387fb5f

Please sign in to comment.