chore: Make field declarations explicit

This used to be valid code:

```
class Foo {
  constructor() {
    this.bar = ‘string’;
  }
}
```

This will now fail since ‘bar’ is not explicitly
defined as a field. We now have to write:

```
class Foo {
  bar:string; // << REQUIRED
  constructor() {
    this.bar = ‘string’;
  }
}
```
This commit is contained in:
Misko Hevery
2014-11-21 21:19:23 -08:00
committed by vsavkin
parent ab961b327e
commit 044625a098
69 changed files with 572 additions and 504 deletions

View File

@ -6,6 +6,8 @@ class Inject {}
class Bar {}
class Provide {
token;
@CONST()
constructor(token) {
this.token = token;
@ -13,6 +15,8 @@ class Provide {
}
class AnnotateMe {
maybe;
@CONST()
constructor({maybe = 'default'} = {}) {
this.maybe = maybe;

View File

@ -13,6 +13,8 @@ var max = (a, b) => {
};
class LexicalThis {
zero;
constructor() {
this.zero = 0;
}

View File

@ -1,9 +1,10 @@
import {ddescribe, describe, it, expect} from 'test_lib/test_lib';
import {CONST} from './fixtures/annotations';
// Constructor
// Define fields
class Foo {
a;
b;
constructor(a, b) {
this.a = a;
this.b = b;
@ -15,6 +16,8 @@ class Foo {
}
class SubFoo extends Foo {
c;
constructor(a, b) {
this.c = 3;
super(a, b);
@ -25,6 +28,8 @@ class SubFoo extends Foo {
class ConstClass {}
class Const {
a;
@CONST
constructor(a:number) {
this.a = a;
@ -32,6 +37,8 @@ class Const {
}
class SubConst extends Const {
b;
@CONST
constructor(a:number, b:number) {
super(a);

View File

@ -5,6 +5,8 @@ function sum(a, b) {
}
class ConstructorWithNamedParams {
sum;
constructor(a, {b=1, c=2}) {
this.sum = a + b + c;
}

View File

@ -30,6 +30,9 @@ class Bar {
}
class Foo {
a;
b;
constructor(a: number, b: number) {
this.a = a;
this.b = b;

View File

@ -25,7 +25,6 @@ import {
} from 'traceur/src/syntax/trees/ParseTrees';
import {
ClassFieldDeclaration,
PropertyConstructorAssignment
} from '../syntax/trees/ParseTrees';
@ -73,30 +72,6 @@ export class ClassTransformer extends ParseTreeTransformer {
// Rename "constructor" to the class name.
elementTree.name.literalToken.value = className;
// Collect all fields, defined in the constructor.
elementTree.body.statements.forEach(function(statement) {
var exp = statement.expression;
if (exp &&
exp.type === BINARY_EXPRESSION &&
exp.operator.type === EQUAL &&
exp.left.type === MEMBER_EXPRESSION &&
exp.left.operand.type === THIS_EXPRESSION) {
var typeAnnotation;
if (exp.right.type === IDENTIFIER_EXPRESSION) {
// `this.field = variable;`
// we can infer the type of the field from the variable when it is a typed arg
var varName = exp.right.getStringValue();
typeAnnotation = argumentTypesMap[varName] || null;
}
var fieldName = exp.left.memberName.value;
var lvalue = new BindingIdentifier(tree.location, fieldName);
fields.push(new ClassFieldDeclaration(tree.location, lvalue, typeAnnotation, isConst));
}
});
// Compute the initializer list
var initializerList = [];
var superCall = that._extractSuperCall(elementTree.body);
@ -149,6 +124,11 @@ export class ClassTransformer extends ParseTreeTransformer {
// Add the field definitions to the beginning of the class.
tree.elements = fields.concat(tree.elements);
if (isConst) {
tree.elements.forEach(function(element) {
element.isFinal = true;
});
}
return super.transformClassDeclaration(tree);
}

View File

@ -45,8 +45,11 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
}
if (tree.typeAnnotation === null) {
this.write_(VAR);
this.write_(tree.isFinal ? 'final' : VAR);
} else {
if (tree.isFinal) {
this.write_('final');
}
this.writeType_(tree.typeAnnotation);
}
this.writeSpace_();
@ -211,6 +214,7 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
case 'number': return 'num';
case 'boolean': return 'bool';
case 'string': return 'String';
case 'any': return 'dynamic';
case 'Promise': return 'Future';
default: return typeName;
}
@ -244,25 +248,6 @@ export class DartParseTreeWriter extends JavaScriptParseTreeWriter {
}
}
visitClassFieldDeclaration(tree) {
if (tree.isFinal) {
// `final <type> name;` or `final name;` for untyped variable
this.write_('final');
this.writeSpace_();
this.writeType_(tree.typeAnnotation);
} else {
// `<type> name;` or `var name;`
if (tree.typeAnnotation) {
this.writeType_(tree.typeAnnotation);
} else {
this.write_(VAR);
this.writeSpace_();
}
}
this.write_(tree.lvalue.getStringValue());
this.write_(SEMI_COLON);
}
writeType_(typeAnnotation) {
if (!typeAnnotation) {

View File

@ -4,36 +4,6 @@ import {PropertyMethodAssignment} from 'traceur/src/syntax/trees/ParseTrees';
import * as ParseTreeType from './ParseTreeType';
// Class field declaration
export class ClassFieldDeclaration extends ParseTree {
constructor(location, lvalue, typeAnnotation, isFinal) {
this.location = location;
this.lvalue = lvalue;
this.typeAnnotation = typeAnnotation;
this.isFinal = isFinal;
}
get type() {
return CLASS_FIELD_DECLARATION;
}
visit(visitor) {
if (visitor.visitClassFieldDeclaration) {
visitor.visitClassFieldDeclaration(this);
}
}
transform(transformer) {
if (transformer.transformClassFieldDeclaration) {
return transformer.transformClassFieldDeclaration(this);
}
return this;
}
}
var CLASS_FIELD_DECLARATION = ParseTreeType.CLASS_FIELD_DECLARATION;
// Class constructor
export class PropertyConstructorAssignment extends PropertyMethodAssignment {
/**