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

@ -0,0 +1,115 @@
import {ABSTRACT, CONST, normalizeBlank} from 'facade/lang';
import {List} from 'facade/collection';
import {TemplateConfig} from './template_config';
@ABSTRACT()
export class Directive {
selector:any; //string;
bind:any;
lightDomServices:any; //List;
implementsTypes:any; //List;
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:string,
bind:any,
lightDomServices:List,
implementsTypes:List
}={})
{
this.selector = selector;
this.lightDomServices = lightDomServices;
this.implementsTypes = implementsTypes;
this.bind = bind;
}
}
export class Component extends Directive {
//TODO: vsavkin: uncomment it once the issue with defining fields in a sublass works
template:any; //TemplateConfig;
lightDomServices:any; //List;
shadowDomServices:any; //List;
componentServices:any; //List;
@CONST()
constructor({
selector,
bind,
template,
lightDomServices,
shadowDomServices,
componentServices,
implementsTypes
}:{
selector:String,
bind:Object,
template:TemplateConfig,
lightDomServices:List,
shadowDomServices:List,
componentServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes});
this.template = template;
this.lightDomServices = lightDomServices;
this.shadowDomServices = shadowDomServices;
this.componentServices = componentServices;
}
}
export class Decorator extends Directive {
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:string,
bind:any,
lightDomServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes
});
}
}
export class Template extends Directive {
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:string,
bind:any,
lightDomServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes
});
}
}

View File

@ -1,71 +0,0 @@
import {Directive} from './directive';
import {CONST} from 'facade/lang';
export class Component extends Directive {
@CONST()
constructor({
selector,
bind,
template,
lightDomServices,
shadowDomServices,
componentServices,
implementsTypes
}:{
selector:String,
bind:Object,
template:TemplateConfig,
lightDomServices:List,
shadowDomServices:List,
componentServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes});
this.template = template;
this.lightDomServices = lightDomServices;
this.shadowDomServices = shadowDomServices;
this.componentServices = componentServices;
}
}
///////////////////////////
/*
import 'package:angular/core.dart' as core;
@Component(
selector: 'example',
template: const TemplateConfig(
url: 'example.dart',
uses: const [core.CONFIG],
directives: const [CompA],
formatters: const [Stringify]
),
componentServices: [...],
shadowDomServices: [...]
implementsTypes: const [App]
)
class Example implements App {}
class CompA {}
@Formatter()
class Stringify {}
<CompA>
LightDOM:
</CompA>
CompA ShadowDOM:
<div>
<CompB></CompB>
</div>
CompB SHadowDOM:
<div></div>
*/

View File

@ -1,25 +0,0 @@
import {Directive} from './directive';
import {CONST} from 'facade/lang';
export class Decorator extends Directive {
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:String,
bind:Object,
lightDomServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes
});
}
}

View File

@ -1,25 +0,0 @@
import {ABSTRACT, CONST} from 'facade/lang';
import {List} from 'facade/collection';
@ABSTRACT()
export class Directive {
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:String,
bind:Object,
lightDomServices:List,
implementsTypes:List
}={})
{
this.selector = selector;
this.lightDomServices = lightDomServices;
this.implementsTypes = implementsTypes;
this.bind = bind;
}
}

View File

@ -1,25 +0,0 @@
import {Directive} from './directive';
import {CONST} from 'facade/lang';
export class Template extends Directive {
@CONST()
constructor({
selector,
bind,
lightDomServices,
implementsTypes
}:{
selector:String,
bind:Object,
lightDomServices:List,
implementsTypes:List
}={})
{
super({
selector: selector,
bind: bind,
lightDomServices: lightDomServices,
implementsTypes: implementsTypes
});
}
}

View File

@ -1,7 +1,12 @@
import {ABSTRACT, CONST} from 'facade/lang';
// import {Type, List} from 'facade/lang';
import {ABSTRACT, CONST, Type} from 'facade/lang';
import {List} from 'facade/collection';
export class TemplateConfig {
url:any; //string;
inline:any; //string;
directives:any; //List<Type>;
formatters:any; //List<Type>;
source:any;//List<TemplateConfig>;
@CONST()
constructor({
url,
@ -10,8 +15,8 @@ export class TemplateConfig {
formatters,
source
}: {
url: String,
inline: String,
url: string,
inline: string,
directives: List<Type>,
formatters: List<Type>,
source: List<TemplateConfig>

View File

@ -1,10 +1,12 @@
import {Type, FIELD} from 'facade/lang';
import {Directive} from '../annotations/directive'
import {Directive} from '../annotations/annotations'
/**
* Combination of a type with the Directive annotation
*/
export class AnnotatedType {
type:Type;
annotation:Directive;
constructor(type:Type, annotation:Directive) {
this.annotation = annotation;
this.type = type;

View File

@ -13,7 +13,7 @@ import {CompileElement} from './pipeline/compile_element';
import {createDefaultSteps} from './pipeline/default_steps';
import {TemplateLoader} from './template_loader';
import {AnnotatedType} from './annotated_type';
import {Component} from '../annotations/component';
import {Component} from '../annotations/annotations';
/**
* The compiler loads and translates the html templates of components into
@ -21,6 +21,10 @@ import {Component} from '../annotations/component';
* the CompilePipeline and the CompileSteps.
*/
export class Compiler {
_templateLoader:TemplateLoader;
_reflector: Reflector;
_parser:Parser;
_closureMap:ClosureMap;
constructor(templateLoader:TemplateLoader, reflector: Reflector, parser:Parser, closureMap:ClosureMap) {
this._templateLoader = templateLoader;
this._reflector = reflector;
@ -53,7 +57,7 @@ export class Compiler {
// - templateRoot string
// - precompiled template
// - ProtoView
var annotation: Component = component.annotation;
var annotation:any = component.annotation;
templateRoot = DOM.createTemplate(annotation.template.inline);
}
var pipeline = new CompilePipeline(this.createSteps(component));

View File

@ -2,16 +2,17 @@ import {ProtoElementInjector} from './element_injector';
import {FIELD} from 'facade/lang';
import {MapWrapper} from 'facade/collection';
import {AnnotatedType} from './annotated_type';
// Comment out as dartanalyzer does not look into @FIELD
// import {List} from 'facade/collection';
// import {ProtoView} from './view';
import {List, Map} from 'facade/collection';
import {ProtoView} from './view';
export class ElementBinder {
@FIELD('final protoElementInjector:ProtoElementInjector')
@FIELD('final componentDirective:AnnotatedType')
@FIELD('final templateDirective:AnnotatedType')
@FIELD('final textNodeIndices:List<int>')
@FIELD('hasElementPropertyBindings:bool')
protoElementInjector:ProtoElementInjector;
componentDirective:AnnotatedType;
templateDirective:AnnotatedType;
textNodeIndices:List<int>;
hasElementPropertyBindings:boolean;
nestedProtoView: ProtoView;
events:Map;
constructor(
protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) {
this.protoElementInjector = protoElementInjector;

View File

@ -15,6 +15,8 @@ var _undefined = new Object();
var _staticKeys;
class StaticKeys {
viewId:int;
ngElementId:int;
constructor() {
//TODO: vsavkin Key.annotate(Key.get(View), 'static')
this.viewId = Key.get(View).id;
@ -28,11 +30,11 @@ class StaticKeys {
}
class TreeNode {
@FIELD('_parent:TreeNode')
@FIELD('_head:TreeNode')
@FIELD('_tail:TreeNode')
@FIELD('_next:TreeNode')
@FIELD('_prev:TreeNode')
_parent:TreeNode;
_head:TreeNode;
_tail:TreeNode;
_next:TreeNode;
_prev:TreeNode;
constructor(parent:TreeNode) {
this._parent = parent;
this._head = null;
@ -71,6 +73,7 @@ class TreeNode {
}
class DirectiveDependency extends Dependency {
depth:int;
constructor(key:Key, asPromise:boolean, lazy:boolean, properties:List, depth:int) {
super(key, asPromise, lazy, properties);
this.depth = depth;
@ -90,9 +93,9 @@ class DirectiveDependency extends Dependency {
}
export class PreBuiltObjects {
@FIELD('final view:View')
@FIELD('final element:NgElement')
constructor(view, element:NgElement) {
view:View;
element:NgElement;
constructor(view:View, element:NgElement) {
this.view = view;
this.element = element;
}
@ -119,30 +122,30 @@ ElementInjector:
*/
export class ProtoElementInjector {
@FIELD('_binding0:Binding')
@FIELD('_binding1:Binding')
@FIELD('_binding2:Binding')
@FIELD('_binding3:Binding')
@FIELD('_binding4:Binding')
@FIELD('_binding5:Binding')
@FIELD('_binding6:Binding')
@FIELD('_binding7:Binding')
@FIELD('_binding8:Binding')
@FIELD('_binding9:Binding')
@FIELD('_binding0IsComponent:int')
@FIELD('_key0:int')
@FIELD('_key1:int')
@FIELD('_key2:int')
@FIELD('_key3:int')
@FIELD('_key4:int')
@FIELD('_key5:int')
@FIELD('_key6:int')
@FIELD('_key7:int')
@FIELD('_key8:int')
@FIELD('_key9:int')
@FIELD('final parent:ProtoElementInjector')
@FIELD('final index:int')
@FIELD('view:View')
_binding0:Binding;
_binding1:Binding;
_binding2:Binding;
_binding3:Binding;
_binding4:Binding;
_binding5:Binding;
_binding6:Binding;
_binding7:Binding;
_binding8:Binding;
_binding9:Binding;
_binding0IsComponent:boolean;
_keyId0:int;
_keyId1:int;
_keyId2:int;
_keyId3:int;
_keyId4:int;
_keyId5:int;
_keyId6:int;
_keyId7:int;
_keyId8:int;
_keyId9:int;
parent:ProtoElementInjector;
index:int;
view:View;
constructor(parent:ProtoElementInjector, index:int, bindings:List, firstBindingIsComponent:boolean = false) {
this.parent = parent;
this.index = index;
@ -194,21 +197,23 @@ export class ProtoElementInjector {
}
export class ElementInjector extends TreeNode {
@FIELD('_proto:ProtoElementInjector')
@FIELD('_lightDomAppInjector:Injector')
@FIELD('_shadowDomAppInjector:Injector')
@FIELD('_host:ElementInjector')
@FIELD('_obj0:Object')
@FIELD('_obj1:Object')
@FIELD('_obj2:Object')
@FIELD('_obj3:Object')
@FIELD('_obj4:Object')
@FIELD('_obj5:Object')
@FIELD('_obj6:Object')
@FIELD('_obj7:Object')
@FIELD('_obj8:Object')
@FIELD('_obj9:Object')
@FIELD('_view:View')
_proto:ProtoElementInjector;
_lightDomAppInjector:Injector;
_shadowDomAppInjector:Injector;
_host:ElementInjector;
_obj0:any;
_obj1:any;
_obj2:any;
_obj3:any;
_obj4:any;
_obj5:any;
_obj6:any;
_obj7:any;
_obj8:any;
_obj9:any;
_view:View;
_preBuiltObjects;
_constructionCounter;
constructor(proto:ProtoElementInjector, parent:ElementInjector, host:ElementInjector) {
super(parent);
if (isPresent(parent) && isPresent(host)) {
@ -441,6 +446,7 @@ export class ElementInjector extends TreeNode {
}
class OutOfBoundsAccess extends Error {
message:string;
constructor(index) {
this.message = `Index ${index} is out-of-bounds.`;
}

View File

@ -1,12 +1,18 @@
import {ListWrapper} from 'facade/collection';
import {List, ListWrapper} from 'facade/collection';
import {DOM} from 'facade/dom';
import {CompileElement} from './compile_element';
import {CompileStep} from './compile_step';
/**
* Controls the processing order of elements.
* Right now it only allows to add a parent element.
*/
export class CompileControl {
_steps:List<CompileStep>;
_currentStepIndex:number;
_parent:CompileElement;
_current:CompileElement;
_results;
constructor(steps) {
this._steps = steps;
this._currentStepIndex = 0;

View File

@ -2,9 +2,12 @@ import {List, Map, ListWrapper, MapWrapper} from 'facade/collection';
import {Element, DOM} from 'facade/dom';
import {int, isBlank, isPresent} from 'facade/lang';
import {AnnotatedType} from '../annotated_type';
import {Decorator} from '../../annotations/decorator';
import {Component} from '../../annotations/component';
import {Template} from '../../annotations/template';
import {Decorator} from '../../annotations/annotations';
import {Component} from '../../annotations/annotations';
import {Template} from '../../annotations/annotations';
import {ElementBinder} from '../element_binder';
import {ProtoElementInjector} from '../element_injector';
import {ProtoView} from '../view';
import {ASTWithSource} from 'change_detection/parser/ast';
@ -14,6 +17,21 @@ import {ASTWithSource} from 'change_detection/parser/ast';
* by the CompileSteps starting out with the pure HTMLElement.
*/
export class CompileElement {
element:Element;
_attrs:Map;
_classList:List;
textNodeBindings:Map;
propertyBindings:Map;
eventBindings:Map;
variableBindings:Map;
decoratorDirectives:List<AnnotatedType>;
templateDirective:AnnotatedType;
componentDirective:AnnotatedType;
isViewRoot:boolean;
hasBindings:boolean;
inheritedProtoView:ProtoView;
inheritedProtoElementInjector:ProtoElementInjector;
inheritedElementBinder:ElementBinder;
constructor(element:Element) {
this.element = element;
this._attrs = null;

View File

@ -10,6 +10,7 @@ import {AnnotatedType} from '../annotated_type';
* all elements in a template.
*/
export class CompilePipeline {
_control:CompileControl;
constructor(steps:List<CompileStep>) {
this._control = new CompileControl(steps);
}

View File

@ -5,8 +5,8 @@ import {SelectorMatcher} from '../selector';
import {CssSelector} from '../selector';
import {AnnotatedType} from '../annotated_type';
import {Template} from '../../annotations/template';
import {Component} from '../../annotations/component';
import {Template} from '../../annotations/annotations';
import {Component} from '../../annotations/annotations';
import {CompileStep} from './compile_step';
import {CompileElement} from './compile_element';
import {CompileControl} from './compile_control';
@ -28,6 +28,7 @@ import {Reflector} from '../reflector';
* in the property bindings)
*/
export class DirectiveParser extends CompileStep {
_selectorMatcher:SelectorMatcher;
constructor(directives:List<AnnotatedType>) {
this._selectorMatcher = new SelectorMatcher();
for (var i=0; i<directives.length; i++) {

View File

@ -6,8 +6,7 @@ import {Parser} from 'change_detection/parser/parser';
import {ClosureMap} from 'change_detection/parser/closure_map';
import {ProtoRecordRange} from 'change_detection/record_range';
import {Directive} from '../../annotations/directive';
import {Component} from '../../annotations/component';
import {Component, Directive} from '../../annotations/annotations';
import {AnnotatedType} from '../annotated_type';
import {ProtoView, ElementPropertyMemento, DirectivePropertyMemento} from '../view';
import {ProtoElementInjector} from '../element_injector';
@ -44,12 +43,13 @@ import {CompileControl} from './compile_control';
* with the flag `isViewRoot`.
*/
export class ElementBinderBuilder extends CompileStep {
_closureMap:ClosureMap;
constructor(closureMap:ClosureMap) {
this._closureMap = closureMap;
}
process(parent:CompileElement, current:CompileElement, control:CompileControl) {
var elementBinder;
var elementBinder = null;
if (current.hasBindings) {
var protoView = current.inheritedProtoView;
elementBinder = protoView.bindElement(current.inheritedProtoElementInjector,

View File

@ -23,6 +23,7 @@ var BIND_NAME_REGEXP = RegExpWrapper.create('^(?:(?:(bind)|(let)|(on))-(.+))|\\[
* - CompileElement#variableBindings
*/
export class PropertyBindingParser extends CompileStep {
_parser:Parser;
constructor(parser:Parser) {
this._parser = parser;
}

View File

@ -46,6 +46,7 @@ export function interpolationToExpression(value:string):string {
* - CompileElement#textNodeBindings
*/
export class TextInterpolationParser extends CompileStep {
_parser:Parser;
constructor(parser:Parser) {
this._parser = parser;
}

View File

@ -19,6 +19,7 @@ import {CompileControl} from './compile_control';
* - CompileElement#propertyBindings
*/
export class ViewSplitter extends CompileStep {
_parser:Parser;
constructor(parser:Parser) {
this._parser = parser;
}

View File

@ -1,7 +1,7 @@
library facade.compiler.reflector;
import 'dart:mirrors';
import '../annotations/directive.dart';
import '../annotations/annotations.dart';
import './annotated_type.dart';
import 'package:facade/lang.dart';

View File

@ -1,5 +1,5 @@
import {Type, isPresent, BaseException} from 'facade/lang';
import {Directive} from '../annotations/directive';
import {Directive} from '../annotations/annotations';
import {AnnotatedType} from './annotated_type';
/**

View File

@ -16,6 +16,9 @@ var _SELECTOR_REGEXP =
* of selecting subsets out of them.
*/
export class CssSelector {
element:string;
classNames:List;
attrs:List;
static parse(selector:string):CssSelector {
var cssSelector = new CssSelector();
var matcher = RegExpWrapper.matcher(_SELECTOR_REGEXP, selector);
@ -91,6 +94,13 @@ export class CssSelector {
* are contained in a given CssSelector.
*/
export class SelectorMatcher {
_selectables:List;
_elementMap:Map;
_elementPartialMap:Map;
_classMap:Map;
_classPartialMap:Map;
_attrValueMap:Map;
_attrValuePartialMap:Map;
constructor() {
this._selectables = ListWrapper.create();

View File

@ -5,7 +5,7 @@ import {Promise} from 'facade/async';
* Strategy to load component templates.
*/
export class TemplateLoader {
load(url:String):Promise<Document> {
load(url:string):Promise<Document> {
return null;
}
}

View File

@ -1,5 +1,5 @@
import {DOM, Element, Node, Text, DocumentFragment, TemplateElement} from 'facade/dom';
import {ListWrapper, MapWrapper} from 'facade/collection';
import {ListWrapper, MapWrapper, List} from 'facade/collection';
import {ProtoRecordRange, RecordRange, WatchGroupDispatcher} from 'change_detection/record_range';
import {Record} from 'change_detection/record';
import {AST} from 'change_detection/parser/ast';
@ -9,7 +9,6 @@ import {ElementBinder} from './element_binder';
import {AnnotatedType} from './annotated_type';
import {SetterFn} from 'change_detection/parser/closure_map';
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
import {List} from 'facade/collection';
import {Injector} from 'di/di';
import {NgElement} from 'core/dom/element';
@ -21,16 +20,16 @@ const NG_BINDING_CLASS = 'ng-binding';
@IMPLEMENTS(WatchGroupDispatcher)
export class View {
/// This list matches the _nodes list. It is sparse, since only Elements have ElementInjector
@FIELD('final rootElementInjectors:List<ElementInjector>')
@FIELD('final elementInjectors:List<ElementInjector>')
@FIELD('final bindElements:List<Element>')
@FIELD('final textNodes:List<Text>')
@FIELD('final recordRange:RecordRange')
rootElementInjectors:List<ElementInjector>;
elementInjectors:List<ElementInjector>;
bindElements:List<Element>;
textNodes:List<Text>;
recordRange:RecordRange;
/// When the view is part of render tree, the DocumentFragment is empty, which is why we need
/// to keep track of the nodes.
@FIELD('final nodes:List<Node>')
@FIELD('final onChangeDispatcher:OnChangeDispatcher')
@FIELD('childViews: List<View>')
nodes:List<Node>;
onChangeDispatcher:OnChangeDispatcher;
childViews: List<View>;
constructor(nodes:List<Node>, elementInjectors:List,
rootElementInjectors:List, textNodes:List, bindElements:List,
protoRecordRange:ProtoRecordRange, context) {
@ -70,9 +69,12 @@ export class View {
}
export class ProtoView {
@FIELD('final element:Element')
@FIELD('final elementBinders:List<ElementBinder>')
@FIELD('final protoRecordRange:ProtoRecordRange')
element:Element;
elementBinders:List<ElementBinder>;
protoRecordRange:ProtoRecordRange;
variableBindings: Map;
textNodesWithBindingCount:int;
elementsWithBindingCount:int;
constructor(
template:Element,
protoRecordRange:ProtoRecordRange) {
@ -299,8 +301,8 @@ export class ProtoView {
}
export class ElementPropertyMemento {
@FIELD('final _elementIndex:int')
@FIELD('final _propertyName:string')
_elementIndex:int;
_propertyName:string;
constructor(elementIndex:int, propertyName:string) {
this._elementIndex = elementIndex;
this._propertyName = propertyName;
@ -313,10 +315,10 @@ export class ElementPropertyMemento {
}
export class DirectivePropertyMemento {
@FIELD('final _elementInjectorIndex:int')
@FIELD('final _directiveIndex:int')
@FIELD('final _setterName:string')
@FIELD('final _setter:SetterFn')
_elementInjectorIndex:int;
_directiveIndex:int;
_setterName:string;
_setter:SetterFn;
constructor(
elementInjectorIndex:number,
directiveIndex:number,
@ -341,8 +343,8 @@ export class DirectivePropertyMemento {
// notify is called by change detection, but done is called by our wrapper on detect changes.
export class OnChangeDispatcher {
@FIELD('_lastView:View')
@FIELD('_lastTarget:DirectivePropertyMemento')
_lastView:View;
_lastTarget:DirectivePropertyMemento;
constructor() {
this._lastView = null;
this._lastTarget = null;

View File

@ -1,9 +1,7 @@
/**
* Define public API for Angular here
*/
export * from './annotations/directive';
export * from './annotations/decorator';
export * from './annotations/component';
export * from './annotations/annotations';
export * from './annotations/template_config';
export * from './application';

View File

@ -1,4 +1,7 @@
import {Element} from 'facade/dom';
export class NgElement {
domElement:Element;
constructor(domElement) {
this.domElement = domElement;
}

View File

@ -1,16 +1,18 @@
import {FIELD} from 'facade/lang';
import {OnChangeDispatcher} from '../compiler/view';
import {ChangeDetector} from 'change_detection/change_detector';
export class LifeCycle {
@FIELD('final _changeDetection:ChangeDetection')
@FIELD('final _onChangeDispatcher:OnChangeDispatcher')
_changeDetector:ChangeDetector;
_onChangeDispatcher:OnChangeDispatcher;
constructor() {
this._changeDetection = null;
this._changeDetector = null;
this._onChangeDispatcher = null;
}
digest() {
_changeDetection.detectChanges();
_changeDetector.detectChanges();
_onChangeDispatcher.done();
}
}