Skip to content

Commit 8e6326f

Browse files
Tommy Odomvsavkin
authored andcommitted
feat(transpiler): allow @const annotation on class
Closes angular#148
1 parent 0a766f4 commit 8e6326f

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

tools/transpiler/spec/classes_spec.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class SubFoo extends Foo {
2121
}
2222
}
2323

24+
@CONST
25+
class ConstClass {}
26+
2427
class Const {
2528
@CONST
2629
constructor(a:number) {
@@ -62,6 +65,11 @@ export function main() {
6265
expect(subConst.b).toBe(2);
6366
});
6467

68+
it('@CONST on class without constructor should generate const constructor', function () {
69+
var constClass = new ConstClass();
70+
expect(constClass).not.toBe(null);
71+
});
72+
6573
describe('inheritance', function() {
6674
it('should support super call', function () {
6775
var subFoo = new SubFoo(1, 2);

tools/transpiler/src/codegeneration/ClassTransformer.js

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {propName} from 'traceur/src/staticsemantics/PropName';
1919
import {
2020
BinaryExpression,
2121
BindingIdentifier,
22+
FormalParameterList,
23+
FunctionBody,
2224
IdentifierExpression
2325
} from 'traceur/src/syntax/trees/ParseTrees';
2426

@@ -48,15 +50,16 @@ export class ClassTransformer extends ParseTreeTransformer {
4850
var argumentTypesMap = {};
4951
var fields = [];
5052
var isConst;
53+
var hasConstructor = false;
5154
var that = this;
5255

5356
tree.elements.forEach(function(elementTree, index) {
5457
if (elementTree.type === PROPERTY_METHOD_ASSIGNMENT &&
5558
!elementTree.isStatic &&
5659
propName(elementTree) === CONSTRUCTOR) {
5760

58-
isConst = elementTree.annotations.some((annotation) =>
59-
annotation.name.identifierToken.value === 'CONST');
61+
hasConstructor = true;
62+
isConst = elementTree.annotations.some(that._isConstAnnotation);
6063

6164
// Store constructor argument types,
6265
// so that we can use them to set the types of simple-assigned fields.
@@ -124,6 +127,26 @@ export class ClassTransformer extends ParseTreeTransformer {
124127
}
125128
});
126129

130+
// If no constructor exists then look to see if we should create a const constructor
131+
// when the class is annotated with @CONST.
132+
if (!hasConstructor) {
133+
let constClassAnnotation = this._extractConstAnnotation(tree);
134+
if (constClassAnnotation !== null) {
135+
tree.elements = [(new PropertyConstructorAssignment(
136+
constClassAnnotation.location,
137+
false,
138+
null,
139+
tree.name,
140+
new FormalParameterList(constClassAnnotation.location, []),
141+
null,
142+
[constClassAnnotation],
143+
new FunctionBody(constClassAnnotation.location, []),
144+
true,
145+
[]
146+
))].concat(tree.elements);
147+
}
148+
}
149+
127150
// Add the field definitions to the beginning of the class.
128151
tree.elements = fields.concat(tree.elements);
129152

@@ -183,4 +206,32 @@ export class ClassTransformer extends ParseTreeTransformer {
183206
body.statements = statements;
184207
return superCall;
185208
}
209+
210+
/**
211+
* Extract the @CONST annotation from the class annotations.
212+
* When found the annotation is removed from the class annotations and returned.
213+
*/
214+
_extractConstAnnotation(tree) {
215+
var annotations = [];
216+
var constAnnotation = null;
217+
var that = this;
218+
219+
tree.annotations.forEach((annotation) => {
220+
if (that._isConstAnnotation(annotation)) {
221+
constAnnotation = annotation;
222+
} else {
223+
annotations.push(annotation);
224+
}
225+
});
226+
227+
tree.annotations = annotations;
228+
return constAnnotation;
229+
}
230+
/**
231+
* Returns true if the annotation is @CONST
232+
*/
233+
_isConstAnnotation(annotation) {
234+
return annotation.name.identifierToken.value === 'CONST';
235+
}
236+
186237
}

0 commit comments

Comments
 (0)