diff --git a/modules/angular2/change_detection.js b/modules/angular2/change_detection.ts similarity index 52% rename from modules/angular2/change_detection.js rename to modules/angular2/change_detection.ts index e36ae08fda..bca66576e8 100644 --- a/modules/angular2/change_detection.js +++ b/modules/angular2/change_detection.ts @@ -6,17 +6,40 @@ */ export { - ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver + ASTWithSource, + AST, + AstTransformer, + AccessMember, + LiteralArray, + ImplicitReceiver } from './src/change_detection/parser/ast'; export {Lexer} from './src/change_detection/parser/lexer'; export {Parser} from './src/change_detection/parser/parser'; export {Locals} from './src/change_detection/parser/locals'; -export {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './src/change_detection/exceptions'; -export {ProtoChangeDetector, ChangeDispatcher, ChangeDetector, ChangeDetection} from './src/change_detection/interfaces'; -export {CHECK_ONCE, CHECK_ALWAYS, DETACHED, CHECKED, ON_PUSH, DEFAULT} from './src/change_detection/constants'; -export {DynamicProtoChangeDetector, JitProtoChangeDetector} from './src/change_detection/proto_change_detector'; +export { + ExpressionChangedAfterItHasBeenChecked, + ChangeDetectionError +} from './src/change_detection/exceptions'; +export { + ProtoChangeDetector, + ChangeDispatcher, + ChangeDetector, + ChangeDetection +} from './src/change_detection/interfaces'; +export { + CHECK_ONCE, + CHECK_ALWAYS, + DETACHED, + CHECKED, + ON_PUSH, + DEFAULT +} from './src/change_detection/constants'; +export { + DynamicProtoChangeDetector, + JitProtoChangeDetector +} from './src/change_detection/proto_change_detector'; export {BindingRecord} from './src/change_detection/binding_record'; export {DirectiveIndex, DirectiveRecord} from './src/change_detection/directive_record'; export {DynamicChangeDetector} from './src/change_detection/dynamic_change_detector'; @@ -25,5 +48,13 @@ export {PipeRegistry} from './src/change_detection/pipes/pipe_registry'; export {uninitialized} from './src/change_detection/change_detection_util'; export {WrappedValue, Pipe} from './src/change_detection/pipes/pipe'; export { - defaultPipes, DynamicChangeDetection, JitChangeDetection, defaultPipeRegistry + defaultPipes, + DynamicChangeDetection, + JitChangeDetection, + defaultPipeRegistry } from './src/change_detection/change_detection'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; diff --git a/modules/angular2/src/change_detection/abstract_change_detector.js b/modules/angular2/src/change_detection/abstract_change_detector.ts similarity index 52% rename from modules/angular2/src/change_detection/abstract_change_detector.js rename to modules/angular2/src/change_detection/abstract_change_detector.ts index 896f623b7b..542b222144 100644 --- a/modules/angular2/src/change_detection/abstract_change_detector.js +++ b/modules/angular2/src/change_detection/abstract_change_detector.ts @@ -4,12 +4,17 @@ import {ChangeDetectorRef} from './change_detector_ref'; import {ChangeDetector} from './interfaces'; import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + export class AbstractChangeDetector extends ChangeDetector { - lightDomChildren:List; - shadowDomChildren:List; - parent:ChangeDetector; - mode:string; - ref:ChangeDetectorRef; + lightDomChildren: List; + shadowDomChildren: List; + parent: ChangeDetector; + mode: string; + ref: ChangeDetectorRef; constructor() { super(); @@ -19,37 +24,27 @@ export class AbstractChangeDetector extends ChangeDetector { this.mode = null; } - addChild(cd:ChangeDetector) { + addChild(cd: ChangeDetector) { ListWrapper.push(this.lightDomChildren, cd); cd.parent = this; } - removeChild(cd:ChangeDetector) { - ListWrapper.remove(this.lightDomChildren, cd); - } + removeChild(cd: ChangeDetector) { ListWrapper.remove(this.lightDomChildren, cd); } - addShadowDomChild(cd:ChangeDetector) { + addShadowDomChild(cd: ChangeDetector) { ListWrapper.push(this.shadowDomChildren, cd); cd.parent = this; } - removeShadowDomChild(cd:ChangeDetector) { - ListWrapper.remove(this.shadowDomChildren, cd); - } + removeShadowDomChild(cd: ChangeDetector) { ListWrapper.remove(this.shadowDomChildren, cd); } - remove() { - this.parent.removeChild(this); - } + remove() { this.parent.removeChild(this); } - detectChanges() { - this._detectChanges(false); - } + detectChanges() { this._detectChanges(false); } - checkNoChanges() { - this._detectChanges(true); - } + checkNoChanges() { this._detectChanges(true); } - _detectChanges(throwOnChange:boolean) { + _detectChanges(throwOnChange: boolean) { if (this.mode === DETACHED || this.mode === CHECKED) return; this.detectChangesInRecords(throwOnChange); @@ -63,30 +58,28 @@ export class AbstractChangeDetector extends ChangeDetector { if (this.mode === CHECK_ONCE) this.mode = CHECKED; } - detectChangesInRecords(throwOnChange:boolean){} - callOnAllChangesDone(){} + detectChangesInRecords(throwOnChange: boolean) {} + callOnAllChangesDone() {} - _detectChangesInLightDomChildren(throwOnChange:boolean) { + _detectChangesInLightDomChildren(throwOnChange: boolean) { var c = this.lightDomChildren; - for(var i = 0; i < c.length; ++i) { + for (var i = 0; i < c.length; ++i) { c[i]._detectChanges(throwOnChange); } } - _detectChangesInShadowDomChildren(throwOnChange:boolean) { + _detectChangesInShadowDomChildren(throwOnChange: boolean) { var c = this.shadowDomChildren; - for(var i = 0; i < c.length; ++i) { + for (var i = 0; i < c.length; ++i) { c[i]._detectChanges(throwOnChange); } } - markAsCheckOnce() { - this.mode = CHECK_ONCE; - } + markAsCheckOnce() { this.mode = CHECK_ONCE; } markPathToRootAsCheckOnce() { - var c = this; - while(isPresent(c) && c.mode != DETACHED) { + var c: ChangeDetector = this; + while (isPresent(c) && c.mode != DETACHED) { if (c.mode === CHECKED) c.mode = CHECK_ONCE; c = c.parent; } diff --git a/modules/angular2/src/change_detection/binding_record.js b/modules/angular2/src/change_detection/binding_record.js deleted file mode 100644 index dbfd815ab9..0000000000 --- a/modules/angular2/src/change_detection/binding_record.js +++ /dev/null @@ -1,68 +0,0 @@ -import {isPresent, isBlank} from 'angular2/src/facade/lang'; -import {SetterFn} from 'angular2/src/reflection/types'; -import {AST} from './parser/ast'; -import {DirectiveIndex, DirectiveRecord} from './directive_record'; - -const DIRECTIVE="directive"; -const ELEMENT="element"; -const TEXT_NODE="textNode"; - -export class BindingRecord { - mode:string; - ast:AST; - - implicitReceiver:any; //number | DirectiveIndex - elementIndex:number; - propertyName:string; - setter:SetterFn; - - directiveRecord:DirectiveRecord; - - constructor(mode:string, implicitReceiver:any, ast:AST, elementIndex:number, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) { - this.mode = mode; - this.implicitReceiver = implicitReceiver; - this.ast = ast; - - this.elementIndex = elementIndex; - this.propertyName = propertyName; - this.setter = setter; - - this.directiveRecord = directiveRecord; - } - - callOnChange() { - return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange; - } - - isOnPushChangeDetection() { - return isPresent(this.directiveRecord) && this.directiveRecord.isOnPushChangeDetection(); - } - - isDirective() { - return this.mode === DIRECTIVE; - } - - isElement() { - return this.mode === ELEMENT; - } - - isTextNode() { - return this.mode === TEXT_NODE; - } - - static createForDirective(ast:AST, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) { - return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, setter, directiveRecord); - } - - static createForElement(ast:AST, elementIndex:number, propertyName:string) { - return new BindingRecord(ELEMENT, 0, ast, elementIndex, propertyName, null, null); - } - - static createForHostProperty(directiveIndex:DirectiveIndex, ast:AST, propertyName:string) { - return new BindingRecord(ELEMENT, directiveIndex, ast, directiveIndex.elementIndex, propertyName, null, null); - } - - static createForTextNode(ast:AST, elementIndex:number) { - return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null); - } -} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/binding_record.ts b/modules/angular2/src/change_detection/binding_record.ts new file mode 100644 index 0000000000..3362191ff5 --- /dev/null +++ b/modules/angular2/src/change_detection/binding_record.ts @@ -0,0 +1,49 @@ +import {isPresent, isBlank} from 'angular2/src/facade/lang'; +import {SetterFn} from 'angular2/src/reflection/types'; +import {AST} from './parser/ast'; +import {DirectiveIndex, DirectiveRecord} from './directive_record'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +const DIRECTIVE = "directive"; +const ELEMENT = "element"; +const TEXT_NODE = "textNode"; + +export class BindingRecord { + constructor(public mode: string, public implicitReceiver: any, public ast: AST, + public elementIndex: number, public propertyName: string, public setter: SetterFn, + public directiveRecord: DirectiveRecord) {} + + callOnChange() { return isPresent(this.directiveRecord) && this.directiveRecord.callOnChange; } + + isOnPushChangeDetection() { + return isPresent(this.directiveRecord) && this.directiveRecord.isOnPushChangeDetection(); + } + + isDirective() { return this.mode === DIRECTIVE; } + + isElement() { return this.mode === ELEMENT; } + + isTextNode() { return this.mode === TEXT_NODE; } + + static createForDirective(ast: AST, propertyName: string, setter: SetterFn, + directiveRecord: DirectiveRecord) { + return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, setter, directiveRecord); + } + + static createForElement(ast: AST, elementIndex: number, propertyName: string) { + return new BindingRecord(ELEMENT, 0, ast, elementIndex, propertyName, null, null); + } + + static createForHostProperty(directiveIndex: DirectiveIndex, ast: AST, propertyName: string) { + return new BindingRecord(ELEMENT, directiveIndex, ast, directiveIndex.elementIndex, + propertyName, null, null); + } + + static createForTextNode(ast: AST, elementIndex: number) { + return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null); + } +} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/change_detection.js b/modules/angular2/src/change_detection/change_detection.js deleted file mode 100644 index dc1ec515f3..0000000000 --- a/modules/angular2/src/change_detection/change_detection.js +++ /dev/null @@ -1,96 +0,0 @@ -import {DynamicProtoChangeDetector, JitProtoChangeDetector} from './proto_change_detector'; -import {PipeFactory} from './pipes/pipe'; -import {PipeRegistry} from './pipes/pipe_registry'; -import {IterableChangesFactory} from './pipes/iterable_changes'; -import {KeyValueChangesFactory} from './pipes/keyvalue_changes'; -import {AsyncPipeFactory} from './pipes/async_pipe'; -import {NullPipeFactory} from './pipes/null_pipe'; -import {BindingRecord} from './binding_record'; -import {DirectiveRecord} from './directive_record'; -import {DEFAULT} from './constants'; -import {ChangeDetection, ProtoChangeDetector} from './interfaces'; -import {Injectable} from 'angular2/src/di/annotations_impl'; -import {List} from 'angular2/src/facade/collection'; - -/** - * Structural diffing for `Object`s and `Map`s. - * - * @exportedAs angular2/pipes - */ -export var keyValDiff:List = [ - new KeyValueChangesFactory(), - new NullPipeFactory() -]; - -/** - * Structural diffing for `Iterable` types such as `Array`s. - * - * @exportedAs angular2/pipes - */ -export var iterableDiff:List = [ - new IterableChangesFactory(), - new NullPipeFactory() -]; - -/** - * Async binding to such types as Observable. - * - * @exportedAs angular2/pipes - */ -export var async:List = [ - new AsyncPipeFactory(), - new NullPipeFactory() -]; - -export var defaultPipes:Map> = { - "iterableDiff" : iterableDiff, - "keyValDiff" : keyValDiff, - "async" : async -}; - - -/** - * Implements change detection that does not require `eval()`. - * - * This is slower than {@link JitChangeDetection}. - * - * @exportedAs angular2/change_detection - */ -@Injectable() -export class DynamicChangeDetection extends ChangeDetection { - registry:PipeRegistry; - - constructor(registry:PipeRegistry) { - super(); - this.registry = registry; - } - - createProtoChangeDetector(name:string, bindingRecords:List, variableBindings:List, - directiveRecords:List, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{ - return new DynamicProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy); - } -} - -/** - * Implements faster change detection, by generating source code. - * - * This requires `eval()`. For change detection that does not require `eval()`, see {@link DynamicChangeDetection}. - * - * @exportedAs angular2/change_detection - */ -@Injectable() -export class JitChangeDetection extends ChangeDetection { - registry:PipeRegistry; - - constructor(registry:PipeRegistry) { - super(); - this.registry = registry; - } - - createProtoChangeDetector(name:string, bindingRecords:List, variableBindings:List, - directiveRecords:List, changeControlStrategy:string = DEFAULT):ProtoChangeDetector{ - return new JitProtoChangeDetector(this.registry, bindingRecords, variableBindings, directiveRecords, changeControlStrategy); - } -} - -export var defaultPipeRegistry:PipeRegistry = new PipeRegistry(defaultPipes); diff --git a/modules/angular2/src/change_detection/change_detection.ts b/modules/angular2/src/change_detection/change_detection.ts new file mode 100644 index 0000000000..12dabe6959 --- /dev/null +++ b/modules/angular2/src/change_detection/change_detection.ts @@ -0,0 +1,88 @@ +import {DynamicProtoChangeDetector, JitProtoChangeDetector} from './proto_change_detector'; +import {PipeFactory} from './pipes/pipe'; +import {PipeRegistry} from './pipes/pipe_registry'; +import {IterableChangesFactory} from './pipes/iterable_changes'; +import {KeyValueChangesFactory} from './pipes/keyvalue_changes'; +import {AsyncPipeFactory} from './pipes/async_pipe'; +import {NullPipeFactory} from './pipes/null_pipe'; +import {BindingRecord} from './binding_record'; +import {DirectiveRecord} from './directive_record'; +import {DEFAULT} from './constants'; +import {ChangeDetection, ProtoChangeDetector} from './interfaces'; +import {Injectable} from 'angular2/src/di/decorators'; +import {List} from 'angular2/src/facade/collection'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +/** + * Structural diffing for `Object`s and `Map`s. + * + * @exportedAs angular2/pipes + */ +export var keyValDiff: List < PipeFactory >= [new KeyValueChangesFactory(), new NullPipeFactory()]; + +/** + * Structural diffing for `Iterable` types such as `Array`s. + * + * @exportedAs angular2/pipes + */ +export var iterableDiff: List < + PipeFactory >= [new IterableChangesFactory(), new NullPipeFactory()]; + +/** + * Async binding to such types as Observable. + * + * @exportedAs angular2/pipes + */ +export var async: List < PipeFactory >= [new AsyncPipeFactory(), new NullPipeFactory()]; + +export var defaultPipes = { + "iterableDiff": iterableDiff, + "keyValDiff": keyValDiff, + "async": async +}; + + +/** + * Implements change detection that does not require `eval()`. + * + * This is slower than {@link JitChangeDetection}. + * + * @exportedAs angular2/change_detection + */ +@Injectable() +export class DynamicChangeDetection extends ChangeDetection { + constructor(public registry: PipeRegistry) { super(); } + + createProtoChangeDetector(name: string, bindingRecords: List, + variableBindings: List, directiveRecords: List, + changeControlStrategy: string = DEFAULT): ProtoChangeDetector { + return new DynamicProtoChangeDetector(this.registry, bindingRecords, variableBindings, + directiveRecords, changeControlStrategy); + } +} + +/** + * Implements faster change detection, by generating source code. + * + * This requires `eval()`. For change detection that does not require `eval()`, see {@link + *DynamicChangeDetection}. + * + * @exportedAs angular2/change_detection + */ +@Injectable() +export class JitChangeDetection extends ChangeDetection { + constructor(public registry: PipeRegistry) { super(); } + + createProtoChangeDetector(name: string, bindingRecords: List, + variableBindings: List, directiveRecords: List, + changeControlStrategy: string = DEFAULT): ProtoChangeDetector { + return new JitProtoChangeDetector(this.registry, bindingRecords, variableBindings, + directiveRecords, changeControlStrategy); + } +} + +export var defaultPipeRegistry: PipeRegistry = new PipeRegistry(defaultPipes); diff --git a/modules/angular2/src/change_detection/change_detection_jit_generator.es6 b/modules/angular2/src/change_detection/change_detection_jit_generator.ts similarity index 67% rename from modules/angular2/src/change_detection/change_detection_jit_generator.es6 rename to modules/angular2/src/change_detection/change_detection_jit_generator.ts index 88bb1f4f6e..4c9fe0082d 100644 --- a/modules/angular2/src/change_detection/change_detection_jit_generator.es6 +++ b/modules/angular2/src/change_detection/change_detection_jit_generator.ts @@ -18,7 +18,13 @@ import { RECORD_TYPE_PIPE, RECORD_TYPE_BINDING_PIPE, RECORD_TYPE_INTERPOLATE - } from './proto_record'; +} from './proto_record'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + /** * The code generator takes a list of proto records and creates a function/class @@ -43,8 +49,8 @@ var MODE_ACCESSOR = "this.mode"; var TEMP_LOCAL = "temp"; var CURRENT_PROTO = "currentProto"; -function typeTemplate(type:string, cons:string, detectChanges:string, - notifyOnAllChangesDone:string, setContext:string):string { +function typeTemplate(type: string, cons: string, detectChanges: string, + notifyOnAllChangesDone: string, setContext: string): string { return ` ${cons} ${detectChanges} @@ -57,7 +63,7 @@ return function(dispatcher, pipeRegistry) { `; } -function constructorTemplate(type:string, fieldsDefinitions:string):string { +function constructorTemplate(type: string, fieldsDefinitions: string): string { return ` var ${type} = function ${type}(dispatcher, pipeRegistry, protos, directiveRecords) { ${ABSTRACT_CHANGE_DETECTOR}.call(this); @@ -73,20 +79,23 @@ ${type}.prototype = Object.create(${ABSTRACT_CHANGE_DETECTOR}.prototype); `; } -function pipeOnDestroyTemplate(pipeNames:List) { +function pipeOnDestroyTemplate(pipeNames: List) { return pipeNames.map((p) => `${p}.onDestroy()`).join("\n"); } -function hydrateTemplate(type:string, mode:string, fieldDefinitions:string, pipeOnDestroy:string, - directiveFieldNames:List, detectorFieldNames:List):string { +function hydrateTemplate(type: string, mode: string, fieldDefinitions: string, + pipeOnDestroy: string, directiveFieldNames: List, + detectorFieldNames: List): string { var directiveInit = ""; - for(var i = 0; i < directiveFieldNames.length; ++i) { - directiveInit += `${directiveFieldNames[i]} = directives.getDirectiveFor(this.directiveRecords[${i}].directiveIndex);\n`; + for (var i = 0; i < directiveFieldNames.length; ++i) { + directiveInit += + `${directiveFieldNames[i]} = directives.getDirectiveFor(this.directiveRecords[${i}].directiveIndex);\n`; } var detectorInit = ""; - for(var i = 0; i < detectorFieldNames.length; ++i) { - detectorInit += `${detectorFieldNames[i]} = directives.getDetectorFor(this.directiveRecords[${i}].directiveIndex);\n`; + for (var i = 0; i < detectorFieldNames.length; ++i) { + detectorInit += + `${detectorFieldNames[i]} = directives.getDetectorFor(this.directiveRecords[${i}].directiveIndex);\n`; } return ` @@ -108,7 +117,7 @@ ${type}.prototype.hydrated = function() { `; } -function detectChangesTemplate(type:string, body:string):string { +function detectChangesTemplate(type: string, body: string): string { return ` ${type}.prototype.detectChangesInRecords = function(throwOnChange) { ${body} @@ -116,7 +125,7 @@ ${type}.prototype.detectChangesInRecords = function(throwOnChange) { `; } -function callOnAllChangesDoneTemplate(type:string, body:string):string { +function callOnAllChangesDoneTemplate(type: string, body: string): string { return ` ${type}.prototype.callOnAllChangesDone = function() { ${body} @@ -124,12 +133,13 @@ ${type}.prototype.callOnAllChangesDone = function() { `; } -function onAllChangesDoneTemplate(directive:string):string { +function onAllChangesDoneTemplate(directive: string): string { return `${directive}.onAllChangesDone();`; } -function detectChangesBodyTemplate(localDefinitions:string, changeDefinitions:string, records:string):string { +function detectChangesBodyTemplate(localDefinitions: string, changeDefinitions: string, + records: string): string { return ` ${localDefinitions} ${changeDefinitions} @@ -143,9 +153,10 @@ ${records} `; } -function pipeCheckTemplate(protoIndex:number, context:string, bindingPropagationConfig:string, pipe:string, pipeType:string, - oldValue:string, newValue:string, change:string, update:string, - addToChanges, lastInDirective:string):string{ +function pipeCheckTemplate(protoIndex: number, context: string, bindingPropagationConfig: string, + pipe: string, pipeType: string, oldValue: string, newValue: string, + change: string, update: string, addToChanges, + lastInDirective: string): string { return ` ${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}]; if (${pipe} === ${UTIL}.unitialized()) { @@ -167,8 +178,9 @@ ${lastInDirective} `; } -function referenceCheckTemplate(protoIndex:number, assignment:string, oldValue:string, newValue:string, change:string, - update:string, addToChanges:string, lastInDirective:string):string { +function referenceCheckTemplate(protoIndex: number, assignment: string, oldValue: string, + newValue: string, change: string, update: string, + addToChanges: string, lastInDirective: string): string { return ` ${CURRENT_PROTO} = ${PROTOS_ACCESSOR}[${protoIndex}]; ${assignment} @@ -182,23 +194,23 @@ ${lastInDirective} `; } -function assignmentTemplate(field:string, value:string) { +function assignmentTemplate(field: string, value: string) { return `${field} = ${value};`; } -function localDefinitionsTemplate(names:List):string { +function localDefinitionsTemplate(names: List): string { return names.map((n) => `var ${n};`).join("\n"); } -function changeDefinitionsTemplate(names:List):string { +function changeDefinitionsTemplate(names: List): string { return names.map((n) => `var ${n} = false;`).join("\n"); } -function fieldDefinitionsTemplate(names:List):string { +function fieldDefinitionsTemplate(names: List): string { return names.map((n) => `${n} = ${UTIL}.unitialized();`).join("\n"); } -function ifChangedGuardTemplate(changeNames:List, body:string):string { +function ifChangedGuardTemplate(changeNames: List, body: string): string { var cond = changeNames.join(" || "); return ` if (${cond}) { @@ -207,11 +219,12 @@ if (${cond}) { `; } -function addToChangesTemplate(oldValue:string, newValue:string):string { +function addToChangesTemplate(oldValue: string, newValue: string): string { return `${CHANGES_LOCAL} = ${UTIL}.addChange(${CHANGES_LOCAL}, ${CURRENT_PROTO}.bindingRecord.propertyName, ${UTIL}.simpleChange(${oldValue}, ${newValue}));`; } -function updateDirectiveTemplate(oldValue:string, newValue:string, directiveProperty:string):string { +function updateDirectiveTemplate(oldValue: string, newValue: string, + directiveProperty: string): string { return ` if(throwOnChange) ${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue})); ${directiveProperty} = ${newValue}; @@ -219,15 +232,15 @@ ${IS_CHANGED_LOCAL} = true; `; } -function updateElementTemplate(oldValue:string, newValue:string):string { +function updateElementTemplate(oldValue: string, newValue: string): string { return ` if(throwOnChange) ${UTIL}.throwOnChange(${CURRENT_PROTO}, ${UTIL}.simpleChange(${oldValue}, ${newValue})); ${DISPATCHER_ACCESSOR}.notifyOnBinding(${CURRENT_PROTO}.bindingRecord, ${newValue}); `; } -function notifyOnChangesTemplate(directive:string):string{ - return ` +function notifyOnChangesTemplate(directive: string): string { + return ` if(${CHANGES_LOCAL}) { ${directive}.onChange(${CHANGES_LOCAL}); ${CHANGES_LOCAL} = null; @@ -235,16 +248,16 @@ if(${CHANGES_LOCAL}) { `; } -function notifyOnPushDetectorsTemplate(detector:string):string{ - return ` +function notifyOnPushDetectorsTemplate(detector: string): string { + return ` if(${IS_CHANGED_LOCAL}) { ${detector}.markAsCheckOnce(); } `; } -function lastInDirectiveTemplate(notifyOnChanges:string, notifyOnPush:string):string{ - return ` +function lastInDirectiveTemplate(notifyOnChanges: string, notifyOnPush: string): string { + return ` ${notifyOnChanges} ${notifyOnPush} ${IS_CHANGED_LOCAL} = false; @@ -253,28 +266,20 @@ ${IS_CHANGED_LOCAL} = false; export class ChangeDetectorJITGenerator { - typeName:string; - records:List; - directiveRecords:List; - localNames:List; - changeNames:List; - fieldNames:List; - pipeNames:List; - changeDetectionStrategy:stirng; - - constructor(typeName:string, changeDetectionStrategy:string, records:List, directiveRecords:List) { - this.typeName = typeName; - this.changeDetectionStrategy = changeDetectionStrategy; - this.records = records; - this.directiveRecords = directiveRecords; + localNames: List; + changeNames: List; + fieldNames: List; + pipeNames: List; + constructor(public typeName: string, public changeDetectionStrategy: string, + public records: List, public directiveRecords: List) { this.localNames = this.getLocalNames(records); this.changeNames = this.getChangeNames(this.localNames); this.fieldNames = this.getFieldNames(this.localNames); this.pipeNames = this.getPipeNames(this.localNames); } - getLocalNames(records:List):List { + getLocalNames(records: List): List { var index = 0; var names = records.map((r) => { var sanitizedName = r.name.replace(new RegExp("\\W", "g"), ''); @@ -283,51 +288,49 @@ export class ChangeDetectorJITGenerator { return ["context"].concat(names); } - getChangeNames(localNames:List):List { + getChangeNames(localNames: List): List { return localNames.map((n) => `change_${n}`); } - getFieldNames(localNames:List):List { + getFieldNames(localNames: List): List { return localNames.map((n) => `this.${n}`); } - getPipeNames(localNames:List):List { + getPipeNames(localNames: List): List { return localNames.map((n) => `this.${n}_pipe`); } - generate():Function { + generate(): Function { var text = typeTemplate(this.typeName, this.genConstructor(), this.genDetectChanges(), - this.genCallOnAllChangesDone(), this.genHydrate()); - return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', 'directiveRecords', text) - (AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveRecords); + this.genCallOnAllChangesDone(), this.genHydrate()); + return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', + 'directiveRecords', text)(AbstractChangeDetector, ChangeDetectionUtil, + this.records, this.directiveRecords); } - genConstructor():string { + genConstructor(): string { return constructorTemplate(this.typeName, this.genFieldDefinitions()); } - genHydrate():string { + genHydrate(): string { var mode = ChangeDetectionUtil.changeDetectionMode(this.changeDetectionStrategy); return hydrateTemplate(this.typeName, mode, this.genFieldDefinitions(), - pipeOnDestroyTemplate(this.getNonNullPipeNames()), - this.getDirectiveFieldNames(), this.getDetectorFieldNames()); + pipeOnDestroyTemplate(this.getNonNullPipeNames()), + this.getDirectiveFieldNames(), this.getDetectorFieldNames()); } - getDirectiveFieldNames():List { + getDirectiveFieldNames(): List { return this.directiveRecords.map((d) => this.getDirective(d.directiveIndex)); } - getDetectorFieldNames():List { - return this.directiveRecords.filter(r => r.isOnPushChangeDetection()).map((d) => this.getDetector(d.directiveIndex)); + getDetectorFieldNames(): List { + return this.directiveRecords.filter(r => r.isOnPushChangeDetection()) + .map((d) => this.getDetector(d.directiveIndex)); } - getDirective(d:DirectiveIndex) { - return `this.directive_${d.name}`; - } + getDirective(d: DirectiveIndex) { return `this.directive_${d.name}`; } - getDetector(d:DirectiveIndex) { - return `this.detector_${d.name}`; - } + getDetector(d: DirectiveIndex) { return `this.detector_${d.name}`; } genFieldDefinitions() { var fields = []; @@ -338,7 +341,7 @@ export class ChangeDetectorJITGenerator { return fieldDefinitionsTemplate(fields); } - getNonNullPipeNames():List { + getNonNullPipeNames(): List { var pipes = []; this.records.forEach((r) => { if (r.mode === RECORD_TYPE_PIPE || r.mode === RECORD_TYPE_BINDING_PIPE) { @@ -348,12 +351,12 @@ export class ChangeDetectorJITGenerator { return pipes; } - genDetectChanges():string { + genDetectChanges(): string { var body = this.genDetectChangesBody(); return detectChangesTemplate(this.typeName, body); } - genCallOnAllChangesDone():string { + genCallOnAllChangesDone(): string { var notifications = []; var dirs = this.directiveRecords; @@ -368,28 +371,24 @@ export class ChangeDetectorJITGenerator { return callOnAllChangesDoneTemplate(this.typeName, notifications.join(";\n")); } - genDetectChangesBody():string { + genDetectChangesBody(): string { var rec = this.records.map((r) => this.genRecord(r)).join("\n"); return detectChangesBodyTemplate(this.genLocalDefinitions(), this.genChangeDefinitions(), rec); } - genLocalDefinitions():string { - return localDefinitionsTemplate(this.localNames); - } + genLocalDefinitions(): string { return localDefinitionsTemplate(this.localNames); } - genChangeDefinitions():string { - return changeDefinitionsTemplate(this.changeNames); - } + genChangeDefinitions(): string { return changeDefinitionsTemplate(this.changeNames); } - genRecord(r:ProtoRecord):string { + genRecord(r: ProtoRecord): string { if (r.mode === RECORD_TYPE_PIPE || r.mode === RECORD_TYPE_BINDING_PIPE) { - return this.genPipeCheck (r); + return this.genPipeCheck(r); } else { return this.genReferenceCheck(r); } } - genPipeCheck(r:ProtoRecord):string { + genPipeCheck(r: ProtoRecord): string { var context = this.localNames[r.contextIndex]; var oldValue = this.fieldNames[r.selfIndex]; var newValue = this.localNames[r.selfIndex]; @@ -402,11 +401,11 @@ export class ChangeDetectorJITGenerator { var addToChanges = this.genAddToChanges(r); var lastInDirective = this.genLastInDirective(r); - return pipeCheckTemplate(r.selfIndex - 1, context, cdRef, pipe, r.name, oldValue, newValue, change, - update, addToChanges, lastInDirective); + return pipeCheckTemplate(r.selfIndex - 1, context, cdRef, pipe, r.name, oldValue, newValue, + change, update, addToChanges, lastInDirective); } - genReferenceCheck(r:ProtoRecord):string { + genReferenceCheck(r: ProtoRecord): string { var oldValue = this.fieldNames[r.selfIndex]; var newValue = this.localNames[r.selfIndex]; var change = this.changeNames[r.selfIndex]; @@ -417,7 +416,7 @@ export class ChangeDetectorJITGenerator { var lastInDirective = this.genLastInDirective(r); var check = referenceCheckTemplate(r.selfIndex - 1, assignment, oldValue, newValue, change, - update, addToChanges, lastInDirective); + update, addToChanges, lastInDirective); if (r.isPureFunction()) { return this.ifChangedGuard(r, check); } else { @@ -425,7 +424,7 @@ export class ChangeDetectorJITGenerator { } } - genUpdateCurrentValue(r:ProtoRecord):string { + genUpdateCurrentValue(r: ProtoRecord): string { var context = this.getContext(r); var newValue = this.localNames[r.selfIndex]; var args = this.genArgs(r); @@ -464,7 +463,7 @@ export class ChangeDetectorJITGenerator { } } - getContext(r:ProtoRecord):string { + getContext(r: ProtoRecord): string { if (r.contextIndex == -1) { return this.getDirective(r.directiveIndex); } else { @@ -472,11 +471,11 @@ export class ChangeDetectorJITGenerator { } } - ifChangedGuard(r:ProtoRecord, body:string):string { + ifChangedGuard(r: ProtoRecord, body: string): string { return ifChangedGuardTemplate(r.args.map((a) => this.changeNames[a]), body); } - genInterpolation(r:ProtoRecord):string{ + genInterpolation(r: ProtoRecord): string { var res = ""; for (var i = 0; i < r.args.length; ++i) { res += this.genLiteral(r.fixedArgs[i]); @@ -488,38 +487,37 @@ export class ChangeDetectorJITGenerator { return res; } - genLiteral(value):string { - return JSON.stringify(value); - } + genLiteral(value): string { return JSON.stringify(value); } - genUpdateDirectiveOrElement(r:ProtoRecord):string { - if (! r.lastInBinding) return ""; + genUpdateDirectiveOrElement(r: ProtoRecord): string { + if (!r.lastInBinding) return ""; var newValue = this.localNames[r.selfIndex]; var oldValue = this.fieldNames[r.selfIndex]; var br = r.bindingRecord; if (br.isDirective()) { - var directiveProperty = `${this.getDirective(br.directiveRecord.directiveIndex)}.${br.propertyName}`; + var directiveProperty = + `${this.getDirective(br.directiveRecord.directiveIndex)}.${br.propertyName}`; return updateDirectiveTemplate(oldValue, newValue, directiveProperty); } else { return updateElementTemplate(oldValue, newValue); } } - genAddToChanges(r:ProtoRecord):string { + genAddToChanges(r: ProtoRecord): string { var newValue = this.localNames[r.selfIndex]; var oldValue = this.fieldNames[r.selfIndex]; return r.bindingRecord.callOnChange() ? addToChangesTemplate(oldValue, newValue) : ""; } - genLastInDirective(r:ProtoRecord):string{ + genLastInDirective(r: ProtoRecord): string { var onChanges = this.genNotifyOnChanges(r); var onPush = this.genNotifyOnPushDetectors(r); return lastInDirectiveTemplate(onChanges, onPush); } - genNotifyOnChanges(r:ProtoRecord):string{ + genNotifyOnChanges(r: ProtoRecord): string { var br = r.bindingRecord; if (r.lastInDirective && br.callOnChange()) { return notifyOnChangesTemplate(this.getDirective(br.directiveRecord.directiveIndex)); @@ -528,7 +526,7 @@ export class ChangeDetectorJITGenerator { } } - genNotifyOnPushDetectors(r:ProtoRecord):string{ + genNotifyOnPushDetectors(r: ProtoRecord): string { var br = r.bindingRecord; if (r.lastInDirective && br.isOnPushChangeDetection()) { return notifyOnPushDetectorsTemplate(this.getDetector(br.directiveRecord.directiveIndex)); @@ -537,11 +535,5 @@ export class ChangeDetectorJITGenerator { } } - genArgs(r:ProtoRecord):string { - return r.args.map((arg) => this.localNames[arg]).join(", "); - } + genArgs(r: ProtoRecord): string { return r.args.map((arg) => this.localNames[arg]).join(", "); } } - - - - diff --git a/modules/angular2/src/change_detection/change_detection_util.js b/modules/angular2/src/change_detection/change_detection_util.js deleted file mode 100644 index effecb7c46..0000000000 --- a/modules/angular2/src/change_detection/change_detection_util.js +++ /dev/null @@ -1,139 +0,0 @@ -import {isPresent, isBlank, BaseException, Type} from 'angular2/src/facade/lang'; -import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; -import {ProtoRecord} from './proto_record'; -import {ExpressionChangedAfterItHasBeenChecked} from './exceptions'; -import {WrappedValue} from './pipes/pipe'; -import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; - -export var uninitialized = new Object(); - -export class SimpleChange { - previousValue:any; - currentValue:any; - - constructor(previousValue:any, currentValue:any) { - this.previousValue = previousValue; - this.currentValue = currentValue; - } -} - -var _simpleChangesIndex = 0; -var _simpleChanges = [ - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null), - new SimpleChange(null, null) -]; - -function _simpleChange(previousValue, currentValue) { - var index = _simpleChangesIndex++ % 20; - var s = _simpleChanges[index]; - s.previousValue = previousValue; - s.currentValue = currentValue; - return s; -} - -export class ChangeDetectionUtil { - static unitialized() { - return uninitialized; - } - - static arrayFn0() { return []; } - static arrayFn1(a1) { return [a1]; } - static arrayFn2(a1, a2) { return [a1, a2]; } - static arrayFn3(a1, a2, a3) { return [a1, a2, a3]; } - static arrayFn4(a1, a2, a3, a4) { return [a1, a2, a3, a4]; } - static arrayFn5(a1, a2, a3, a4, a5) { return [a1, a2, a3, a4, a5]; } - static arrayFn6(a1, a2, a3, a4, a5, a6) { return [a1, a2, a3, a4, a5, a6]; } - static arrayFn7(a1, a2, a3, a4, a5, a6, a7) { return [a1, a2, a3, a4, a5, a6, a7]; } - static arrayFn8(a1, a2, a3, a4, a5, a6, a7, a8) { return [a1, a2, a3, a4, a5, a6, a7, a8]; } - static arrayFn9(a1, a2, a3, a4, a5, a6, a7, a8, a9) { return [a1, a2, a3, a4, a5, a6, a7, a8, a9]; } - - static operation_negate(value) {return !value;} - static operation_add(left, right) {return left + right;} - static operation_subtract(left, right) {return left - right;} - static operation_multiply(left, right) {return left * right;} - static operation_divide(left, right) {return left / right;} - static operation_remainder(left, right) {return left % right;} - static operation_equals(left, right) {return left == right;} - static operation_not_equals(left, right) {return left != right;} - static operation_less_then(left, right) {return left < right;} - static operation_greater_then(left, right) {return left > right;} - static operation_less_or_equals_then(left, right) {return left <= right;} - static operation_greater_or_equals_then(left, right) {return left >= right;} - static operation_logical_and(left, right) {return left && right;} - static operation_logical_or(left, right) {return left || right;} - static cond(cond, trueVal, falseVal) {return cond ? trueVal : falseVal;} - - static mapFn(keys:List) { - function buildMap(values) { - var res = StringMapWrapper.create(); - for(var i = 0; i < keys.length; ++i) { - StringMapWrapper.set(res, keys[i], values[i]); - } - return res; - } - - switch (keys.length) { - case 0: return () => []; - case 1: return (a1) => buildMap([a1]); - case 2: return (a1, a2) => buildMap([a1, a2]); - case 3: return (a1, a2, a3) => buildMap([a1, a2, a3]); - case 4: return (a1, a2, a3, a4) => buildMap([a1, a2, a3, a4]); - case 5: return (a1, a2, a3, a4, a5) => buildMap([a1, a2, a3, a4, a5]); - case 6: return (a1, a2, a3, a4, a5, a6) => buildMap([a1, a2, a3, a4, a5, a6]); - case 7: return (a1, a2, a3, a4, a5, a6, a7) => buildMap([a1, a2, a3, a4, a5, a6, a7]); - case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) => buildMap([a1, a2, a3, a4, a5, a6, a7, a8]); - case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => buildMap([a1, a2, a3, a4, a5, a6, a7, a8, a9]); - default: throw new BaseException(`Does not support literal maps with more than 9 elements`); - } - } - - static keyedAccess(obj, args) { - return obj[args[0]]; - } - - static unwrapValue(value:any):any { - if (value instanceof WrappedValue) { - return value.wrapped; - } else { - return value; - } - } - - static throwOnChange(proto:ProtoRecord, change) { - throw new ExpressionChangedAfterItHasBeenChecked(proto, change); - } - - static changeDetectionMode(strategy:string) { - return strategy == ON_PUSH ? CHECK_ONCE : CHECK_ALWAYS; - } - - static simpleChange(previousValue:any, currentValue:any):SimpleChange { - return _simpleChange(previousValue, currentValue); - } - - static addChange(changes, propertyName:string, change){ - if (isBlank(changes)) { - changes = {}; - } - changes[propertyName] = change; - return changes; - } -} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/change_detection_util.ts b/modules/angular2/src/change_detection/change_detection_util.ts new file mode 100644 index 0000000000..758dac627c --- /dev/null +++ b/modules/angular2/src/change_detection/change_detection_util.ts @@ -0,0 +1,148 @@ +import {isPresent, isBlank, BaseException, Type} from 'angular2/src/facade/lang'; +import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; +import {ProtoRecord} from './proto_record'; +import {ExpressionChangedAfterItHasBeenChecked} from './exceptions'; +import {WrappedValue} from './pipes/pipe'; +import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export var uninitialized = new Object(); + +export class SimpleChange { + constructor(public previousValue: any, public currentValue: any) {} +} + +var _simpleChangesIndex = 0; +var _simpleChanges = [ + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null), + new SimpleChange(null, null) +]; + +function _simpleChange(previousValue, currentValue) { + var index = _simpleChangesIndex++ % 20; + var s = _simpleChanges[index]; + s.previousValue = previousValue; + s.currentValue = currentValue; + return s; +} + +export class ChangeDetectionUtil { + static unitialized() { return uninitialized; } + + static arrayFn0() { return []; } + static arrayFn1(a1) { return [a1]; } + static arrayFn2(a1, a2) { return [a1, a2]; } + static arrayFn3(a1, a2, a3) { return [a1, a2, a3]; } + static arrayFn4(a1, a2, a3, a4) { return [a1, a2, a3, a4]; } + static arrayFn5(a1, a2, a3, a4, a5) { return [a1, a2, a3, a4, a5]; } + static arrayFn6(a1, a2, a3, a4, a5, a6) { return [a1, a2, a3, a4, a5, a6]; } + static arrayFn7(a1, a2, a3, a4, a5, a6, a7) { return [a1, a2, a3, a4, a5, a6, a7]; } + static arrayFn8(a1, a2, a3, a4, a5, a6, a7, a8) { return [a1, a2, a3, a4, a5, a6, a7, a8]; } + static arrayFn9(a1, a2, a3, a4, a5, a6, a7, a8, a9) { + return [a1, a2, a3, a4, a5, a6, a7, a8, a9]; + } + + static operation_negate(value) { return !value; } + static operation_add(left, right) { return left + right; } + static operation_subtract(left, right) { return left - right; } + static operation_multiply(left, right) { return left * right; } + static operation_divide(left, right) { return left / right; } + static operation_remainder(left, right) { return left % right; } + static operation_equals(left, right) { return left == right; } + static operation_not_equals(left, right) { return left != right; } + static operation_less_then(left, right) { return left < right; } + static operation_greater_then(left, right) { return left > right; } + static operation_less_or_equals_then(left, right) { return left <= right; } + static operation_greater_or_equals_then(left, right) { return left >= right; } + static operation_logical_and(left, right) { return left && right; } + static operation_logical_or(left, right) { return left || right; } + static cond(cond, trueVal, falseVal) { return cond ? trueVal : falseVal; } + + static mapFn(keys: List) { + function buildMap(values) { + var res = StringMapWrapper.create(); + for (var i = 0; i < keys.length; ++i) { + StringMapWrapper.set(res, keys[i], values[i]); + } + return res; + } + + switch (keys.length) { + case 0: + return () => []; + case 1: + return (a1) => buildMap([a1]); + case 2: + return (a1, a2) => buildMap([a1, a2]); + case 3: + return (a1, a2, a3) => buildMap([a1, a2, a3]); + case 4: + return (a1, a2, a3, a4) => buildMap([a1, a2, a3, a4]); + case 5: + return (a1, a2, a3, a4, a5) => buildMap([a1, a2, a3, a4, a5]); + case 6: + return (a1, a2, a3, a4, a5, a6) => buildMap([a1, a2, a3, a4, a5, a6]); + case 7: + return (a1, a2, a3, a4, a5, a6, a7) => buildMap([a1, a2, a3, a4, a5, a6, a7]); + case 8: + return (a1, a2, a3, a4, a5, a6, a7, a8) => buildMap([a1, a2, a3, a4, a5, a6, a7, a8]); + case 9: + return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => + buildMap([a1, a2, a3, a4, a5, a6, a7, a8, a9]); + default: + throw new BaseException(`Does not support literal maps with more than 9 elements`); + } + } + + static keyedAccess(obj, args) { return obj[args[0]]; } + + static unwrapValue(value: any): any { + if (value instanceof WrappedValue) { + return value.wrapped; + } else { + return value; + } + } + + static throwOnChange(proto: ProtoRecord, change) { + throw new ExpressionChangedAfterItHasBeenChecked(proto, change); + } + + static changeDetectionMode(strategy: string) { + return strategy == ON_PUSH ? CHECK_ONCE : CHECK_ALWAYS; + } + + static simpleChange(previousValue: any, currentValue: any): SimpleChange { + return _simpleChange(previousValue, currentValue); + } + + static addChange(changes, propertyName: string, change) { + if (isBlank(changes)) { + changes = {}; + } + changes[propertyName] = change; + return changes; + } +} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/change_detector_ref.js b/modules/angular2/src/change_detection/change_detector_ref.ts similarity index 64% rename from modules/angular2/src/change_detection/change_detector_ref.js rename to modules/angular2/src/change_detection/change_detector_ref.ts index fdfd4f2ec0..75d2e4429b 100644 --- a/modules/angular2/src/change_detection/change_detector_ref.js +++ b/modules/angular2/src/change_detection/change_detector_ref.ts @@ -1,41 +1,40 @@ import {ChangeDetector} from './interfaces'; import {CHECK_ONCE, DETACHED, CHECK_ALWAYS} from './constants'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + /** * Controls change detection. * - * {@link ChangeDetectorRef} allows requesting checks for detectors that rely on observables. It also allows detaching and + * {@link ChangeDetectorRef} allows requesting checks for detectors that rely on observables. It + *also allows detaching and * attaching change detector subtrees. * * @exportedAs angular2/change_detection */ export class ChangeDetectorRef { - _cd:ChangeDetector; - - constructor(cd:ChangeDetector) { - this._cd = cd; - } + constructor(private _cd: ChangeDetector) {} /** * Request to check all ON_PUSH ancestors. */ - requestCheck() { - this._cd.markPathToRootAsCheckOnce(); - } + requestCheck() { this._cd.markPathToRootAsCheckOnce(); } /** * Detaches the change detector from the change detector tree. * * The detached change detector will not be checked until it is reattached. */ - detach() { - this._cd.mode = DETACHED; - } + detach() { this._cd.mode = DETACHED; } /** * Reattach the change detector to the change detector tree. * - * This also requests a check of this change detector. This reattached change detector will be checked during the + * This also requests a check of this change detector. This reattached change detector will be + *checked during the * next change detection run. */ reattach() { diff --git a/modules/angular2/src/change_detection/coalesce.js b/modules/angular2/src/change_detection/coalesce.ts similarity index 52% rename from modules/angular2/src/change_detection/coalesce.js rename to modules/angular2/src/change_detection/coalesce.ts index 2b2e860fcb..2f89d8790a 100644 --- a/modules/angular2/src/change_detection/coalesce.js +++ b/modules/angular2/src/change_detection/coalesce.ts @@ -2,6 +2,11 @@ import {isPresent} from 'angular2/src/facade/lang'; import {List, ListWrapper, Map, MapWrapper} from 'angular2/src/facade/collection'; import {RECORD_TYPE_SELF, ProtoRecord} from './proto_record'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + /** * Removes "duplicate" records. It assuming that record evaluation does not * have side-effects. @@ -12,7 +17,7 @@ import {RECORD_TYPE_SELF, ProtoRecord} from './proto_record'; * Records that are last in bindings CANNOT be removed, and instead are * replaced with very cheap SELF records. */ -export function coalesce(records:List):List { +export function coalesce(records: List): List { var res = ListWrapper.create(); var indexMap = MapWrapper.create(); @@ -37,52 +42,27 @@ export function coalesce(records:List):List { return res; } -function _selfRecord(r:ProtoRecord, contextIndex:number, selfIndex:number):ProtoRecord { - return new ProtoRecord( - RECORD_TYPE_SELF, - "self", - null, - [], - r.fixedArgs, - contextIndex, - r.directiveIndex, - selfIndex, - r.bindingRecord, - r.expressionAsString, - r.lastInBinding, - r.lastInDirective - ); +function _selfRecord(r: ProtoRecord, contextIndex: number, selfIndex: number): ProtoRecord { + return new ProtoRecord(RECORD_TYPE_SELF, "self", null, [], r.fixedArgs, contextIndex, + r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString, + r.lastInBinding, r.lastInDirective); } -function _findMatching(r:ProtoRecord, rs:List){ - return ListWrapper.find(rs, (rr) => - rr.mode === r.mode && - rr.funcOrValue === r.funcOrValue && - rr.contextIndex === r.contextIndex && - ListWrapper.equals(rr.args, r.args) - ); +function _findMatching(r: ProtoRecord, rs: List) { + return ListWrapper.find(rs, (rr) => rr.mode === r.mode && rr.funcOrValue === r.funcOrValue && + rr.contextIndex === r.contextIndex && + ListWrapper.equals(rr.args, r.args)); } -function _replaceIndices(r:ProtoRecord, selfIndex:number, indexMap:Map) { +function _replaceIndices(r: ProtoRecord, selfIndex: number, indexMap: Map) { var args = ListWrapper.map(r.args, (a) => _map(indexMap, a)); var contextIndex = _map(indexMap, r.contextIndex); - return new ProtoRecord( - r.mode, - r.name, - r.funcOrValue, - args, - r.fixedArgs, - contextIndex, - r.directiveIndex, - selfIndex, - r.bindingRecord, - r.expressionAsString, - r.lastInBinding, - r.lastInDirective - ); + return new ProtoRecord(r.mode, r.name, r.funcOrValue, args, r.fixedArgs, contextIndex, + r.directiveIndex, selfIndex, r.bindingRecord, r.expressionAsString, + r.lastInBinding, r.lastInDirective); } -function _map(indexMap:Map, value:number) { - var r = MapWrapper.get(indexMap, value) +function _map(indexMap: Map, value: number) { + var r = MapWrapper.get(indexMap, value); return isPresent(r) ? r : value; } \ No newline at end of file diff --git a/modules/angular2/src/change_detection/constants.js b/modules/angular2/src/change_detection/constants.ts similarity index 65% rename from modules/angular2/src/change_detection/constants.js rename to modules/angular2/src/change_detection/constants.ts index ec91588c38..03e057e71b 100644 --- a/modules/angular2/src/change_detection/constants.js +++ b/modules/angular2/src/change_detection/constants.ts @@ -1,28 +1,33 @@ -//TODO:vsavkin Use enums after switching to TypeScript +// TODO:vsavkin Use enums after switching to TypeScript + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; /** * CHECK_ONCE means that after calling detectChanges the mode of the change detector * will become CHECKED. */ -export const CHECK_ONCE="CHECK_ONCE"; +export const CHECK_ONCE = "CHECK_ONCE"; /** * CHECKED means that the change detector should be skipped until its mode changes to * CHECK_ONCE or CHECK_ALWAYS. */ -export const CHECKED="CHECKED"; +export const CHECKED = "CHECKED"; /** * CHECK_ALWAYS means that after calling detectChanges the mode of the change detector * will remain CHECK_ALWAYS. */ -export const CHECK_ALWAYS="ALWAYS_CHECK"; +export const CHECK_ALWAYS = "ALWAYS_CHECK"; /** * DETACHED means that the change detector sub tree is not a part of the main tree and * should be skipped. */ -export const DETACHED="DETACHED"; +export const DETACHED = "DETACHED"; /** * ON_PUSH means that the change detector's mode will be set to CHECK_ONCE during hydration. diff --git a/modules/angular2/src/change_detection/directive_record.js b/modules/angular2/src/change_detection/directive_record.js deleted file mode 100644 index 9b7ec3c214..0000000000 --- a/modules/angular2/src/change_detection/directive_record.js +++ /dev/null @@ -1,34 +0,0 @@ -import {ON_PUSH} from './constants'; -import {StringWrapper} from 'angular2/src/facade/lang'; - -export class DirectiveIndex { - elementIndex:number; - directiveIndex:number; - - constructor(elementIndex:number, directiveIndex:number) { - this.elementIndex = elementIndex; - this.directiveIndex = directiveIndex; - } - - get name() { - return `${this.elementIndex}_${this.directiveIndex}`; - } -} - -export class DirectiveRecord { - directiveIndex:DirectiveIndex; - callOnAllChangesDone:boolean; - callOnChange:boolean; - changeDetection:string; - - constructor(directiveIndex:DirectiveIndex, callOnAllChangesDone:boolean, callOnChange:boolean, changeDetection:string) { - this.directiveIndex = directiveIndex; - this.callOnAllChangesDone = callOnAllChangesDone; - this.callOnChange = callOnChange; - this.changeDetection = changeDetection; - } - - isOnPushChangeDetection():boolean { - return StringWrapper.equals(this.changeDetection, ON_PUSH); - } -} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/directive_record.ts b/modules/angular2/src/change_detection/directive_record.ts new file mode 100644 index 0000000000..a91bebea7b --- /dev/null +++ b/modules/angular2/src/change_detection/directive_record.ts @@ -0,0 +1,20 @@ +import {ON_PUSH} from './constants'; +import {StringWrapper} from 'angular2/src/facade/lang'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export class DirectiveIndex { + constructor(public elementIndex: number, public directiveIndex: number) {} + + get name() { return `${this.elementIndex}_${this.directiveIndex}`; } +} + +export class DirectiveRecord { + constructor(public directiveIndex: DirectiveIndex, public callOnAllChangesDone: boolean, + public callOnChange: boolean, public changeDetection: string) {} + + isOnPushChangeDetection(): boolean { return StringWrapper.equals(this.changeDetection, ON_PUSH); } +} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/dynamic_change_detector.js b/modules/angular2/src/change_detection/dynamic_change_detector.ts similarity index 75% rename from modules/angular2/src/change_detection/dynamic_change_detector.js rename to modules/angular2/src/change_detection/dynamic_change_detector.ts index db2ec0e8f2..28b88f7e28 100644 --- a/modules/angular2/src/change_detection/dynamic_change_detector.js +++ b/modules/angular2/src/change_detection/dynamic_change_detector.ts @@ -4,7 +4,7 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca import {AbstractChangeDetector} from './abstract_change_detector'; import {BindingRecord} from './binding_record'; import {PipeRegistry} from './pipes/pipe_registry'; -import {ChangeDetectionUtil, uninitialized} from './change_detection_util'; +import {ChangeDetectionUtil, SimpleChange, uninitialized} from './change_detection_util'; import { @@ -20,35 +20,31 @@ import { RECORD_TYPE_PIPE, RECORD_TYPE_BINDING_PIPE, RECORD_TYPE_INTERPOLATE - } from './proto_record'; +} from './proto_record'; import {ExpressionChangedAfterItHasBeenChecked, ChangeDetectionError} from './exceptions'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + export class DynamicChangeDetector extends AbstractChangeDetector { - dispatcher:any; - pipeRegistry; + locals: any; + values: List; + changes: List; + pipes: List; + prevContexts: List; + directives: any; - locals:any; - values:List; - changes:List; - pipes:List; - prevContexts:List; - - protos:List; - directives:any; - directiveRecords:List; - changeControlStrategy:string; - - constructor(changeControlStrategy:string, dispatcher:any, pipeRegistry:PipeRegistry, - protoRecords:List, directiveRecords:List) { + constructor(private changeControlStrategy: string, private dispatcher: any, + private pipeRegistry: PipeRegistry, private protos: List, + private directiveRecords: List) { super(); - this.dispatcher = dispatcher; - this.pipeRegistry = pipeRegistry; - - this.values = ListWrapper.createFixedSize(protoRecords.length + 1); - this.pipes = ListWrapper.createFixedSize(protoRecords.length + 1); - this.prevContexts = ListWrapper.createFixedSize(protoRecords.length + 1); - this.changes = ListWrapper.createFixedSize(protoRecords.length + 1); + this.values = ListWrapper.createFixedSize(protos.length + 1); + this.pipes = ListWrapper.createFixedSize(protos.length + 1); + this.prevContexts = ListWrapper.createFixedSize(protos.length + 1); + this.changes = ListWrapper.createFixedSize(protos.length + 1); ListWrapper.fill(this.values, uninitialized); ListWrapper.fill(this.pipes, null); @@ -56,13 +52,9 @@ export class DynamicChangeDetector extends AbstractChangeDetector { ListWrapper.fill(this.changes, false); this.locals = null; this.directives = null; - - this.protos = protoRecords; - this.directiveRecords = directiveRecords; - this.changeControlStrategy = changeControlStrategy; } - hydrate(context:any, locals:any, directives:any) { + hydrate(context: any, locals: any, directives: any) { this.mode = ChangeDetectionUtil.changeDetectionMode(this.changeControlStrategy); this.values[0] = context; this.locals = locals; @@ -79,24 +71,22 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } _destroyPipes() { - for(var i = 0; i < this.pipes.length; ++i) { + for (var i = 0; i < this.pipes.length; ++i) { if (isPresent(this.pipes[i])) { this.pipes[i].onDestroy(); } } } - hydrated():boolean { - return this.values[0] !== uninitialized; - } + hydrated(): boolean { return this.values[0] !== uninitialized; } - detectChangesInRecords(throwOnChange:boolean) { - var protos:List = this.protos; + detectChangesInRecords(throwOnChange: boolean) { + var protos: List < ProtoRecord >= this.protos; var changes = null; var isChanged = false; for (var i = 0; i < protos.length; ++i) { - var proto:ProtoRecord = protos[i]; + var proto: ProtoRecord = protos[i]; var bindingRecord = proto.bindingRecord; var directiveRecord = bindingRecord.directiveRecord; @@ -142,7 +132,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _addChange(bindingRecord:BindingRecord, change, changes) { + _addChange(bindingRecord: BindingRecord, change, changes) { if (bindingRecord.callOnChange()) { return ChangeDetectionUtil.addChange(changes, bindingRecord.propertyName, change); } else { @@ -150,15 +140,11 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _getDirectiveFor(directiveIndex) { - return this.directives.getDirectiveFor(directiveIndex); - } + _getDirectiveFor(directiveIndex) { return this.directives.getDirectiveFor(directiveIndex); } - _getDetectorFor(directiveIndex) { - return this.directives.getDetectorFor(directiveIndex); - } + _getDetectorFor(directiveIndex) { return this.directives.getDetectorFor(directiveIndex); } - _check(proto:ProtoRecord) { + _check(proto: ProtoRecord): SimpleChange { try { if (proto.mode === RECORD_TYPE_PIPE || proto.mode === RECORD_TYPE_BINDING_PIPE) { return this._pipeCheck(proto); @@ -170,7 +156,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _referenceCheck(proto:ProtoRecord) { + _referenceCheck(proto: ProtoRecord) { if (this._pureFuncAndArgsDidNotChange(proto)) { this._setChanged(proto, false); return null; @@ -194,7 +180,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _calculateCurrValue(proto:ProtoRecord) { + _calculateCurrValue(proto: ProtoRecord) { switch (proto.mode) { case RECORD_TYPE_SELF: return this._readContext(proto); @@ -230,7 +216,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _pipeCheck(proto:ProtoRecord) { + _pipeCheck(proto: ProtoRecord) { var context = this._readContext(proto); var pipe = this._pipeFor(proto, context); var prevValue = this._readSelf(proto); @@ -254,7 +240,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { } } - _pipeFor(proto:ProtoRecord, context) { + _pipeFor(proto: ProtoRecord, context) { var storedPipe = this._readPipe(proto); if (isPresent(storedPipe) && storedPipe.supports(context)) { return storedPipe; @@ -274,7 +260,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { return pipe; } - _readContext(proto:ProtoRecord) { + _readContext(proto: ProtoRecord) { if (proto.contextIndex == -1) { return this._getDirectiveFor(proto.directiveIndex); } else { @@ -284,33 +270,23 @@ export class DynamicChangeDetector extends AbstractChangeDetector { return this.values[proto.contextIndex]; } - _readSelf(proto:ProtoRecord) { - return this.values[proto.selfIndex]; - } + _readSelf(proto: ProtoRecord) { return this.values[proto.selfIndex]; } - _writeSelf(proto:ProtoRecord, value) { - this.values[proto.selfIndex] = value; - } + _writeSelf(proto: ProtoRecord, value) { this.values[proto.selfIndex] = value; } - _readPipe(proto:ProtoRecord) { - return this.pipes[proto.selfIndex]; - } + _readPipe(proto: ProtoRecord) { return this.pipes[proto.selfIndex]; } - _writePipe(proto:ProtoRecord, value) { - this.pipes[proto.selfIndex] = value; - } + _writePipe(proto: ProtoRecord, value) { this.pipes[proto.selfIndex] = value; } - _setChanged(proto:ProtoRecord, value:boolean) { - this.changes[proto.selfIndex] = value; - } + _setChanged(proto: ProtoRecord, value: boolean) { this.changes[proto.selfIndex] = value; } - _pureFuncAndArgsDidNotChange(proto:ProtoRecord):boolean { + _pureFuncAndArgsDidNotChange(proto: ProtoRecord): boolean { return proto.isPureFunction() && !this._argsChanged(proto); } - _argsChanged(proto:ProtoRecord):boolean { + _argsChanged(proto: ProtoRecord): boolean { var args = proto.args; - for(var i = 0; i < args.length; ++i) { + for (var i = 0; i < args.length; ++i) { if (this.changes[args[i]]) { return true; } @@ -318,7 +294,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector { return false; } - _readArgs(proto:ProtoRecord) { + _readArgs(proto: ProtoRecord) { var res = ListWrapper.createFixedSize(proto.args.length); var args = proto.args; for (var i = 0; i < args.length; ++i) { @@ -334,6 +310,3 @@ function isSame(a, b) { if ((a !== a) && (b !== b)) return true; return false; } - - - diff --git a/modules/angular2/src/change_detection/exceptions.js b/modules/angular2/src/change_detection/exceptions.js deleted file mode 100644 index 818e3aaec4..0000000000 --- a/modules/angular2/src/change_detection/exceptions.js +++ /dev/null @@ -1,33 +0,0 @@ -import {ProtoRecord} from './proto_record'; -import {BaseException} from "angular2/src/facade/lang"; - -export class ExpressionChangedAfterItHasBeenChecked extends BaseException { - message:string; - - constructor(proto:ProtoRecord, change:any) { - super(); - this.message = `Expression '${proto.expressionAsString}' has changed after it was checked. ` + - `Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`; - } - - toString():string { - return this.message; - } -} - -export class ChangeDetectionError extends BaseException { - message:string; - originalException:any; - location:string; - - constructor(proto:ProtoRecord, originalException:any) { - super(); - this.originalException = originalException; - this.location = proto.expressionAsString; - this.message = `${this.originalException} in [${this.location}]`; - } - - toString():string { - return this.message; - } -} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/exceptions.ts b/modules/angular2/src/change_detection/exceptions.ts new file mode 100644 index 0000000000..7796ae69df --- /dev/null +++ b/modules/angular2/src/change_detection/exceptions.ts @@ -0,0 +1,36 @@ +import {ProtoRecord} from './proto_record'; +import {BaseException} from "angular2/src/facade/lang"; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + + +export class ExpressionChangedAfterItHasBeenChecked extends BaseException { + message: string; + + constructor(proto: ProtoRecord, change: any) { + super(); + this.message = + `Expression '${proto.expressionAsString}' has changed after it was checked. ` + + `Previous value: '${change.previousValue}'. Current value: '${change.currentValue}'`; + } + + toString(): string { return this.message; } +} + +export class ChangeDetectionError extends BaseException { + message: string; + originalException: any; + location: string; + + constructor(proto: ProtoRecord, originalException: any) { + super(); + this.originalException = originalException; + this.location = proto.expressionAsString; + this.message = `${this.originalException} in [${this.location}]`; + } + + toString(): string { return this.message; } +} \ No newline at end of file diff --git a/modules/angular2/src/change_detection/interfaces.js b/modules/angular2/src/change_detection/interfaces.ts similarity index 56% rename from modules/angular2/src/change_detection/interfaces.js rename to modules/angular2/src/change_detection/interfaces.ts index 9fe89edd38..5eed193aa7 100644 --- a/modules/angular2/src/change_detection/interfaces.js +++ b/modules/angular2/src/change_detection/interfaces.ts @@ -3,10 +3,13 @@ import {Locals} from './parser/locals'; import {DEFAULT} from './constants'; import {BindingRecord} from './binding_record'; -export class ProtoChangeDetector { - instantiate(dispatcher:any):ChangeDetector{ - return null; - } +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export class ProtoChangeDetector { + instantiate(dispatcher: any): ChangeDetector { return null; } } /** @@ -17,10 +20,12 @@ export class ProtoChangeDetector { * - {@link DynamicChangeDetection}: slower, but does not require `eval()`. * - {@link JitChangeDetection}: faster, but requires `eval()`. * - * In JavaScript, you should always use `JitChangeDetection`, unless you are in an environment that has + * In JavaScript, you should always use `JitChangeDetection`, unless you are in an environment that + *has * [CSP](https://developer.mozilla.org/en-US/docs/Web/Security/CSP), such as a Chrome Extension. * - * In Dart, use `DynamicChangeDetection` during development. The Angular transformer generates an analog to the + * In Dart, use `DynamicChangeDetection` during development. The Angular transformer generates an + *analog to the * `JitChangeDetection` strategy at compile time. * * @@ -33,26 +38,27 @@ export class ProtoChangeDetector { * @exportedAs angular2/change_detection */ export class ChangeDetection { - createProtoChangeDetector(name:string, bindingRecords:List, variableBindings:List, directiveRecords:List, - changeControlStrategy:string=DEFAULT):ProtoChangeDetector{ + createProtoChangeDetector(name: string, bindingRecords: List, variableBindings: List, + directiveRecords: List, + changeControlStrategy: string = DEFAULT): ProtoChangeDetector { return null; } } export class ChangeDispatcher { - notifyOnBinding(bindingRecord:BindingRecord, value:any) {} + notifyOnBinding(bindingRecord: BindingRecord, value: any) {} } export class ChangeDetector { - parent:ChangeDetector; - mode:string; + parent: ChangeDetector; + mode: string; - addChild(cd:ChangeDetector) {} - addShadowDomChild(cd:ChangeDetector) {} - removeChild(cd:ChangeDetector) {} - removeShadowDomChild(cd:ChangeDetector) {} + addChild(cd: ChangeDetector) {} + addShadowDomChild(cd: ChangeDetector) {} + removeChild(cd: ChangeDetector) {} + removeShadowDomChild(cd: ChangeDetector) {} remove() {} - hydrate(context:any, locals:Locals, directives:any) {} + hydrate(context: any, locals: Locals, directives: any) {} dehydrate() {} markPathToRootAsCheckOnce() {} diff --git a/modules/angular2/src/change_detection/parser/ast.js b/modules/angular2/src/change_detection/parser/ast.js deleted file mode 100644 index 7744ef2c3c..0000000000 --- a/modules/angular2/src/change_detection/parser/ast.js +++ /dev/null @@ -1,532 +0,0 @@ -import {autoConvertAdd, isBlank, isPresent, FunctionWrapper, BaseException} from "angular2/src/facade/lang"; -import {List, Map, ListWrapper, StringMapWrapper} from "angular2/src/facade/collection"; - -export class AST { - eval(context, locals) { - throw new BaseException("Not supported"); - } - - get isAssignable():boolean { - return false; - } - - assign(context, locals, value) { - throw new BaseException("Not supported"); - } - - visit(visitor) { - } - - toString():string { - return "AST"; - } -} - -export class EmptyExpr extends AST { - eval(context, locals) { - return null; - } - - visit(visitor) { - //do nothing - } -} - -export class ImplicitReceiver extends AST { - eval(context, locals) { - return context; - } - - visit(visitor) { - return visitor.visitImplicitReceiver(this); - } -} - -/** - * Multiple expressions separated by a semicolon. - */ -export class Chain extends AST { - expressions:List; - constructor(expressions:List) { - super(); - this.expressions = expressions; - } - - eval(context, locals) { - var result; - for (var i = 0; i < this.expressions.length; i++) { - var last = this.expressions[i].eval(context, locals); - if (isPresent(last)) result = last; - } - return result; - } - - visit(visitor) { - return visitor.visitChain(this); - } -} - -export class Conditional extends AST { - condition:AST; - trueExp:AST; - falseExp:AST; - constructor(condition:AST, trueExp:AST, falseExp:AST){ - super(); - this.condition = condition; - this.trueExp = trueExp; - this.falseExp = falseExp; - } - - eval(context, locals) { - if(this.condition.eval(context, locals)) { - return this.trueExp.eval(context, locals); - } else { - return this.falseExp.eval(context, locals); - } - } - - visit(visitor) { - return visitor.visitConditional(this); - } -} - -export class AccessMember extends AST { - receiver:AST; - name:string; - getter:Function; - setter:Function; - constructor(receiver:AST, name:string, getter:Function, setter:Function) { - super(); - this.receiver = receiver; - this.name = name; - this.getter = getter; - this.setter = setter; - } - - eval(context, locals) { - if (this.receiver instanceof ImplicitReceiver && - isPresent(locals) && locals.contains(this.name)) { - return locals.get(this.name); - } else { - var evaluatedReceiver = this.receiver.eval(context, locals); - return this.getter(evaluatedReceiver); - } - } - - get isAssignable():boolean { - return true; - } - - assign(context, locals, value) { - var evaluatedContext = this.receiver.eval(context, locals); - - if (this.receiver instanceof ImplicitReceiver && - isPresent(locals) && locals.contains(this.name)) { - throw new BaseException(`Cannot reassign a variable binding ${this.name}`); - } else { - return this.setter(evaluatedContext, value); - } - } - - visit(visitor) { - return visitor.visitAccessMember(this); - } -} - -export class KeyedAccess extends AST { - obj:AST; - key:AST; - constructor(obj:AST, key:AST) { - super(); - this.obj = obj; - this.key = key; - } - - eval(context, locals) { - var obj = this.obj.eval(context, locals); - var key = this.key.eval(context, locals); - return obj[key]; - } - - get isAssignable():boolean { - return true; - } - - assign(context, locals, value) { - var obj = this.obj.eval(context, locals); - var key = this.key.eval(context, locals); - obj[key] = value; - return value; - } - - visit(visitor) { - return visitor.visitKeyedAccess(this); - } -} - -export class Pipe extends AST { - exp:AST; - name:string; - args:List; - inBinding:boolean; - constructor(exp:AST, name:string, args:List, inBinding:boolean) { - super(); - this.exp = exp; - this.name = name; - this.args = args; - this.inBinding = inBinding; - } - - visit(visitor) { - return visitor.visitPipe(this); - } -} - -export class LiteralPrimitive extends AST { - value; - constructor(value) { - super(); - this.value = value; - } - - eval(context, locals) { - return this.value; - } - - visit(visitor) { - return visitor.visitLiteralPrimitive(this); - } -} - -export class LiteralArray extends AST { - expressions:List; - constructor(expressions:List) { - super(); - this.expressions = expressions; - } - - eval(context, locals) { - return ListWrapper.map(this.expressions, (e) => e.eval(context, locals)); - } - - visit(visitor) { - return visitor.visitLiteralArray(this); - } -} - -export class LiteralMap extends AST { - keys:List; - values:List; - constructor(keys:List, values:List) { - super(); - this.keys = keys; - this.values = values; - } - - eval(context, locals) { - var res = StringMapWrapper.create(); - for(var i = 0; i < this.keys.length; ++i) { - StringMapWrapper.set(res, this.keys[i], this.values[i].eval(context, locals)); - } - return res; - } - - visit(visitor) { - return visitor.visitLiteralMap(this); - } -} - -export class Interpolation extends AST { - strings:List; - expressions:List; - constructor(strings:List, expressions:List) { - super(); - this.strings = strings; - this.expressions = expressions; - } - - eval(context, locals) { - throw new BaseException("evaluating an Interpolation is not supported"); - } - - visit(visitor) { - visitor.visitInterpolation(this); - } -} - -export class Binary extends AST { - operation:string; - left:AST; - right:AST; - constructor(operation:string, left:AST, right:AST) { - super(); - this.operation = operation; - this.left = left; - this.right = right; - } - - eval(context, locals) { - var left = this.left.eval(context, locals); - switch (this.operation) { - case '&&': return left && this.right.eval(context, locals); - case '||': return left || this.right.eval(context, locals); - } - var right = this.right.eval(context, locals); - - switch (this.operation) { - case '+' : return left + right; - case '-' : return left - right; - case '*' : return left * right; - case '/' : return left / right; - case '%' : return left % right; - case '==' : return left == right; - case '!=' : return left != right; - case '===' : return left === right; - case '!==' : return left !== right; - case '<' : return left < right; - case '>' : return left > right; - case '<=' : return left <= right; - case '>=' : return left >= right; - case '^' : return left ^ right; - case '&' : return left & right; - } - throw 'Internal error [$operation] not handled'; - } - - visit(visitor) { - return visitor.visitBinary(this); - } -} - -export class PrefixNot extends AST { - expression:AST; - constructor(expression:AST) { - super(); - this.expression = expression; - } - - eval(context, locals) { - return !this.expression.eval(context, locals); - } - - visit(visitor) { - return visitor.visitPrefixNot(this); - } -} - -export class Assignment extends AST { - target:AST; - value:AST; - constructor(target:AST, value:AST) { - super(); - this.target = target; - this.value = value; - } - - eval(context, locals) { - return this.target.assign(context, locals, this.value.eval(context, locals)); - } - - visit(visitor) { - return visitor.visitAssignment(this); - } -} - -export class MethodCall extends AST { - receiver:AST; - fn:Function; - args:List; - name:string; - constructor(receiver:AST, name:string, fn:Function, args:List) { - super(); - this.receiver = receiver; - this.fn = fn; - this.args = args; - this.name = name; - } - - eval(context, locals) { - var evaluatedArgs = evalList(context, locals, this.args); - if (this.receiver instanceof ImplicitReceiver && - isPresent(locals) && locals.contains(this.name)) { - var fn = locals.get(this.name); - return FunctionWrapper.apply(fn, evaluatedArgs); - } else { - var evaluatedReceiver = this.receiver.eval(context, locals); - return this.fn(evaluatedReceiver, evaluatedArgs); - } - } - - visit(visitor) { - return visitor.visitMethodCall(this); - } -} - -export class FunctionCall extends AST { - target:AST; - args:List; - constructor(target:AST, args:List) { - super(); - this.target = target; - this.args = args; - } - - eval(context, locals) { - var obj = this.target.eval(context, locals); - if (! (obj instanceof Function)) { - throw new BaseException(`${obj} is not a function`); - } - return FunctionWrapper.apply(obj, evalList(context, locals, this.args)); - } - - visit(visitor) { - return visitor.visitFunctionCall(this); - } -} - -export class ASTWithSource extends AST { - ast:AST; - source:string; - location:string; - constructor(ast:AST, source:string, location:string) { - super(); - this.source = source; - this.location = location; - this.ast = ast; - } - - eval(context, locals) { - return this.ast.eval(context, locals); - } - - get isAssignable():boolean { - return this.ast.isAssignable; - } - - assign(context, locals, value) { - return this.ast.assign(context, locals, value); - } - - visit(visitor) { - return this.ast.visit(visitor); - } - - toString():string { - return `${this.source} in ${this.location}`; - } -} - -export class TemplateBinding { - key:string; - keyIsVar:boolean; - name:string; - expression:ASTWithSource; - constructor(key:string, keyIsVar:boolean, name:string, expression:ASTWithSource) { - this.key = key; - this.keyIsVar = keyIsVar; - // only either name or expression will be filled. - this.name = name; - this.expression = expression; - } -} - -//INTERFACE -export class AstVisitor { - visitAccessMember(ast:AccessMember) {} - visitAssignment(ast:Assignment) {} - visitBinary(ast:Binary) {} - visitChain(ast:Chain){} - visitConditional(ast:Conditional) {} - visitPipe(ast:Pipe) {} - visitFunctionCall(ast:FunctionCall) {} - visitImplicitReceiver(ast:ImplicitReceiver) {} - visitKeyedAccess(ast:KeyedAccess) {} - visitLiteralArray(ast:LiteralArray) {} - visitLiteralMap(ast:LiteralMap) {} - visitLiteralPrimitive(ast:LiteralPrimitive) {} - visitMethodCall(ast:MethodCall) {} - visitPrefixNot(ast:PrefixNot) {} -} - -export class AstTransformer { - visitImplicitReceiver(ast:ImplicitReceiver) { - return ast; - } - - visitInterpolation(ast:Interpolation) { - return new Interpolation(ast.strings, this.visitAll(ast.expressions)); - } - - visitLiteralPrimitive(ast:LiteralPrimitive) { - return new LiteralPrimitive(ast.value); - } - - visitAccessMember(ast:AccessMember) { - return new AccessMember(ast.receiver.visit(this), ast.name, ast.getter, ast.setter); - } - - visitMethodCall(ast:MethodCall) { - return new MethodCall(ast.receiver.visit(this), ast.name, ast.fn, this.visitAll(ast.args)); - } - - visitFunctionCall(ast:FunctionCall) { - return new FunctionCall(ast.target.visit(this), this.visitAll(ast.args)); - } - - visitLiteralArray(ast:LiteralArray) { - return new LiteralArray(this.visitAll(ast.expressions)); - } - - visitLiteralMap(ast:LiteralMap) { - return new LiteralMap(ast.keys, this.visitAll(ast.values)); - } - - visitBinary(ast:Binary) { - return new Binary(ast.operation, ast.left.visit(this), ast.right.visit(this)); - } - - visitPrefixNot(ast:PrefixNot) { - return new PrefixNot(ast.expression.visit(this)); - } - - visitConditional(ast:Conditional) { - return new Conditional( - ast.condition.visit(this), - ast.trueExp.visit(this), - ast.falseExp.visit(this) - ); - } - - visitPipe(ast:Pipe) { - return new Pipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.inBinding); - } - - visitKeyedAccess(ast:KeyedAccess) { - return new KeyedAccess(ast.obj.visit(this), ast.key.visit(this)); - } - - visitAll(asts:List) { - var res = ListWrapper.createFixedSize(asts.length); - for (var i = 0; i < asts.length; ++i) { - res[i] = asts[i].visit(this); - } - return res; - } -} - -var _evalListCache = [[],[0],[0,0],[0,0,0],[0,0,0,0],[0,0,0,0,0], - [0,0,0,0,0,0], [0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0], - [0,0,0,0,0,0,0,0,0]]; - -function evalList(context, locals, exps:List){ - var length = exps.length; - if (length > 10) { - throw new BaseException("Cannot have more than 10 argument"); - } - - var result = _evalListCache[length]; - for (var i = 0; i < length; i++) { - result[i] = exps[i].eval(context, locals); - } - return result; -} diff --git a/modules/angular2/src/change_detection/parser/ast.ts b/modules/angular2/src/change_detection/parser/ast.ts new file mode 100644 index 0000000000..d91fbc35b4 --- /dev/null +++ b/modules/angular2/src/change_detection/parser/ast.ts @@ -0,0 +1,388 @@ +import {isBlank, isPresent, FunctionWrapper, BaseException} from "angular2/src/facade/lang"; +import {List, Map, ListWrapper, StringMapWrapper} from "angular2/src/facade/collection"; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export class AST { + eval(context, locals) { throw new BaseException("Not supported"); } + + get isAssignable(): boolean { return false; } + + assign(context, locals, value) { throw new BaseException("Not supported"); } + + visit(visitor): any { return null; } + + toString(): string { return "AST"; } +} + +export class EmptyExpr extends AST { + eval(context, locals) { return null; } + + visit(visitor) { + // do nothing + } +} + +export class ImplicitReceiver extends AST { + eval(context, locals) { return context; } + + visit(visitor) { return visitor.visitImplicitReceiver(this); } +} + +/** + * Multiple expressions separated by a semicolon. + */ +export class Chain extends AST { + constructor(public expressions: List) { super(); } + + eval(context, locals) { + var result; + for (var i = 0; i < this.expressions.length; i++) { + var last = this.expressions[i].eval(context, locals); + if (isPresent(last)) result = last; + } + return result; + } + + visit(visitor) { return visitor.visitChain(this); } +} + +export class Conditional extends AST { + constructor(public condition: AST, public trueExp: AST, public falseExp: AST) { super(); } + + eval(context, locals) { + if (this.condition.eval(context, locals)) { + return this.trueExp.eval(context, locals); + } else { + return this.falseExp.eval(context, locals); + } + } + + visit(visitor) { return visitor.visitConditional(this); } +} + +export class AccessMember extends AST { + constructor(public receiver: AST, public name: string, public getter: Function, + public setter: Function) { + super(); + } + + eval(context, locals) { + if (this.receiver instanceof ImplicitReceiver && isPresent(locals) && + locals.contains(this.name)) { + return locals.get(this.name); + } else { + var evaluatedReceiver = this.receiver.eval(context, locals); + return this.getter(evaluatedReceiver); + } + } + + get isAssignable(): boolean { return true; } + + assign(context, locals, value) { + var evaluatedContext = this.receiver.eval(context, locals); + + if (this.receiver instanceof ImplicitReceiver && isPresent(locals) && + locals.contains(this.name)) { + throw new BaseException(`Cannot reassign a variable binding ${this.name}`); + } else { + return this.setter(evaluatedContext, value); + } + } + + visit(visitor) { return visitor.visitAccessMember(this); } +} + +export class KeyedAccess extends AST { + constructor(public obj: AST, public key: AST) { super(); } + + eval(context, locals) { + var obj: any = this.obj.eval(context, locals); + var key: any = this.key.eval(context, locals); + return obj[key]; + } + + get isAssignable(): boolean { return true; } + + assign(context, locals, value) { + var obj: any = this.obj.eval(context, locals); + var key: any = this.key.eval(context, locals); + obj[key] = value; + return value; + } + + visit(visitor) { return visitor.visitKeyedAccess(this); } +} + +export class Pipe extends AST { + constructor(public exp: AST, public name: string, public args: List, + public inBinding: boolean) { + super(); + } + + visit(visitor) { return visitor.visitPipe(this); } +} + +export class LiteralPrimitive extends AST { + constructor(public value) { super(); } + + eval(context, locals) { return this.value; } + + visit(visitor) { return visitor.visitLiteralPrimitive(this); } +} + +export class LiteralArray extends AST { + constructor(public expressions: List) { super(); } + + eval(context, locals) { + return ListWrapper.map(this.expressions, (e) => e.eval(context, locals)); + } + + visit(visitor) { return visitor.visitLiteralArray(this); } +} + +export class LiteralMap extends AST { + constructor(public keys: List, public values: List) { super(); } + + eval(context, locals) { + var res = StringMapWrapper.create(); + for (var i = 0; i < this.keys.length; ++i) { + StringMapWrapper.set(res, this.keys[i], this.values[i].eval(context, locals)); + } + return res; + } + + visit(visitor) { return visitor.visitLiteralMap(this); } +} + +export class Interpolation extends AST { + constructor(public strings: List, public expressions: List) { super(); } + + eval(context, locals) { throw new BaseException("evaluating an Interpolation is not supported"); } + + visit(visitor) { visitor.visitInterpolation(this); } +} + +export class Binary extends AST { + constructor(public operation: string, public left: AST, public right: AST) { super(); } + + eval(context, locals) { + var left: any = this.left.eval(context, locals); + switch (this.operation) { + case '&&': + return left && this.right.eval(context, locals); + case '||': + return left || this.right.eval(context, locals); + } + var right: any = this.right.eval(context, locals); + + switch (this.operation) { + case '+': + return left + right; + case '-': + return left - right; + case '*': + return left * right; + case '/': + return left / right; + case '%': + return left % right; + case '==': + return left == right; + case '!=': + return left != right; + case '===': + return left === right; + case '!==': + return left !== right; + case '<': + return left < right; + case '>': + return left > right; + case '<=': + return left <= right; + case '>=': + return left >= right; + case '^': + return left ^ right; + case '&': + return left & right; + } + throw 'Internal error [$operation] not handled'; + } + + visit(visitor) { return visitor.visitBinary(this); } +} + +export class PrefixNot extends AST { + constructor(public expression: AST) { super(); } + + eval(context, locals) { return !this.expression.eval(context, locals); } + + visit(visitor) { return visitor.visitPrefixNot(this); } +} + +export class Assignment extends AST { + constructor(public target: AST, public value: AST) { super(); } + + eval(context, locals) { + return this.target.assign(context, locals, this.value.eval(context, locals)); + } + + visit(visitor) { return visitor.visitAssignment(this); } +} + +export class MethodCall extends AST { + constructor(public receiver: AST, public name: string, public fn: Function, + public args: List) { + super(); + } + + eval(context, locals) { + var evaluatedArgs = evalList(context, locals, this.args); + if (this.receiver instanceof ImplicitReceiver && isPresent(locals) && + locals.contains(this.name)) { + var fn = locals.get(this.name); + return FunctionWrapper.apply(fn, evaluatedArgs); + } else { + var evaluatedReceiver = this.receiver.eval(context, locals); + return this.fn(evaluatedReceiver, evaluatedArgs); + } + } + + visit(visitor) { return visitor.visitMethodCall(this); } +} + +export class FunctionCall extends AST { + constructor(public target: AST, public args: List) { super(); } + + eval(context, locals) { + var obj: any = this.target.eval(context, locals); + if (!(obj instanceof Function)) { + throw new BaseException(`${obj} is not a function`); + } + return FunctionWrapper.apply(obj, evalList(context, locals, this.args)); + } + + visit(visitor) { return visitor.visitFunctionCall(this); } +} + +export class ASTWithSource extends AST { + constructor(public ast: AST, public source: string, public location: string) { super(); } + + eval(context, locals) { return this.ast.eval(context, locals); } + + get isAssignable(): boolean { return this.ast.isAssignable; } + + assign(context, locals, value) { return this.ast.assign(context, locals, value); } + + visit(visitor) { return this.ast.visit(visitor); } + + toString(): string { return `${this.source} in ${this.location}`; } +} + +export class TemplateBinding { + constructor(public key: string, public keyIsVar: boolean, public name: string, + public expression: ASTWithSource) {} +} + +// INTERFACE +export class AstVisitor { + visitAccessMember(ast: AccessMember) {} + visitAssignment(ast: Assignment) {} + visitBinary(ast: Binary) {} + visitChain(ast: Chain) {} + visitConditional(ast: Conditional) {} + visitPipe(ast: Pipe) {} + visitFunctionCall(ast: FunctionCall) {} + visitImplicitReceiver(ast: ImplicitReceiver) {} + visitKeyedAccess(ast: KeyedAccess) {} + visitLiteralArray(ast: LiteralArray) {} + visitLiteralMap(ast: LiteralMap) {} + visitLiteralPrimitive(ast: LiteralPrimitive) {} + visitMethodCall(ast: MethodCall) {} + visitPrefixNot(ast: PrefixNot) {} +} + +export class AstTransformer { + visitImplicitReceiver(ast: ImplicitReceiver) { return ast; } + + visitInterpolation(ast: Interpolation) { + return new Interpolation(ast.strings, this.visitAll(ast.expressions)); + } + + visitLiteralPrimitive(ast: LiteralPrimitive) { return new LiteralPrimitive(ast.value); } + + visitAccessMember(ast: AccessMember) { + return new AccessMember(ast.receiver.visit(this), ast.name, ast.getter, ast.setter); + } + + visitMethodCall(ast: MethodCall) { + return new MethodCall(ast.receiver.visit(this), ast.name, ast.fn, this.visitAll(ast.args)); + } + + visitFunctionCall(ast: FunctionCall) { + return new FunctionCall(ast.target.visit(this), this.visitAll(ast.args)); + } + + visitLiteralArray(ast: LiteralArray) { return new LiteralArray(this.visitAll(ast.expressions)); } + + visitLiteralMap(ast: LiteralMap) { return new LiteralMap(ast.keys, this.visitAll(ast.values)); } + + visitBinary(ast: Binary) { + return new Binary(ast.operation, ast.left.visit(this), ast.right.visit(this)); + } + + visitPrefixNot(ast: PrefixNot) { return new PrefixNot(ast.expression.visit(this)); } + + visitConditional(ast: Conditional) { + return new Conditional(ast.condition.visit(this), ast.trueExp.visit(this), + ast.falseExp.visit(this)); + } + + visitPipe(ast: Pipe) { + return new Pipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.inBinding); + } + + visitKeyedAccess(ast: KeyedAccess) { + return new KeyedAccess(ast.obj.visit(this), ast.key.visit(this)); + } + + visitAll(asts: List) { + var res = ListWrapper.createFixedSize(asts.length); + for (var i = 0; i < asts.length; ++i) { + res[i] = asts[i].visit(this); + } + return res; + } +} + +var _evalListCache = [ + [], + [0], + [0, 0], + [0, 0, 0], + [0, 0, 0, 0], + [0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0] +]; + +function evalList(context, locals, exps: List) { + var length = exps.length; + if (length > 10) { + throw new BaseException("Cannot have more than 10 argument"); + } + + var result = _evalListCache[length]; + for (var i = 0; i < length; i++) { + result[i] = exps[i].eval(context, locals); + } + return result; +} diff --git a/modules/angular2/src/change_detection/parser/lexer.js b/modules/angular2/src/change_detection/parser/lexer.js deleted file mode 100644 index ce7f5210ad..0000000000 --- a/modules/angular2/src/change_detection/parser/lexer.js +++ /dev/null @@ -1,476 +0,0 @@ -import {Injectable} from 'angular2/src/di/annotations_impl'; -import {List, ListWrapper, SetWrapper} from "angular2/src/facade/collection"; -import {int, NumberWrapper, StringJoiner, StringWrapper, BaseException} from "angular2/src/facade/lang"; - -export const TOKEN_TYPE_CHARACTER = 1; -export const TOKEN_TYPE_IDENTIFIER = 2; -export const TOKEN_TYPE_KEYWORD = 3; -export const TOKEN_TYPE_STRING = 4; -export const TOKEN_TYPE_OPERATOR = 5; -export const TOKEN_TYPE_NUMBER = 6; - -@Injectable() -export class Lexer { - text:string; - tokenize(text:string):List { - var scanner = new _Scanner(text); - var tokens = []; - var token = scanner.scanToken(); - while (token != null) { - ListWrapper.push(tokens, token); - token = scanner.scanToken(); - } - return tokens; - } -} - -export class Token { - index:int; - type:int; - _numValue:number; - _strValue:string; - constructor(index:int, type:int, numValue:number, strValue:string) { - /** - * NOTE: To ensure that this constructor creates the same hidden class each time, ensure that - * all the fields are assigned to in the exact same order in each run of this constructor. - */ - this.index = index; - this.type = type; - this._numValue = numValue; - this._strValue = strValue; - } - - isCharacter(code:int):boolean { - return (this.type == TOKEN_TYPE_CHARACTER && this._numValue == code); - } - - isNumber():boolean { - return (this.type == TOKEN_TYPE_NUMBER); - } - - isString():boolean { - return (this.type == TOKEN_TYPE_STRING); - } - - isOperator(operater:string):boolean { - return (this.type == TOKEN_TYPE_OPERATOR && this._strValue == operater); - } - - isIdentifier():boolean { - return (this.type == TOKEN_TYPE_IDENTIFIER); - } - - isKeyword():boolean { - return (this.type == TOKEN_TYPE_KEYWORD); - } - - isKeywordVar():boolean { - return (this.type == TOKEN_TYPE_KEYWORD && this._strValue == "var"); - } - - isKeywordNull():boolean { - return (this.type == TOKEN_TYPE_KEYWORD && this._strValue == "null"); - } - - isKeywordUndefined():boolean { - return (this.type == TOKEN_TYPE_KEYWORD && this._strValue == "undefined"); - } - - isKeywordTrue():boolean { - return (this.type == TOKEN_TYPE_KEYWORD && this._strValue == "true"); - } - - isKeywordFalse():boolean { - return (this.type == TOKEN_TYPE_KEYWORD && this._strValue == "false"); - } - - toNumber():number { - // -1 instead of NULL ok? - return (this.type == TOKEN_TYPE_NUMBER) ? this._numValue : -1; - } - - toString():string { - var type:int = this.type; - if (type >= TOKEN_TYPE_CHARACTER && type <= TOKEN_TYPE_STRING) { - return this._strValue; - } else if (type == TOKEN_TYPE_NUMBER) { - return this._numValue.toString(); - } else { - return null; - } - } -} - -function newCharacterToken(index:int, code:int):Token { - return new Token(index, TOKEN_TYPE_CHARACTER, code, StringWrapper.fromCharCode(code)); -} - -function newIdentifierToken(index:int, text:string):Token { - return new Token(index, TOKEN_TYPE_IDENTIFIER, 0, text); -} - -function newKeywordToken(index:int, text:string):Token { - return new Token(index, TOKEN_TYPE_KEYWORD, 0, text); -} - -function newOperatorToken(index:int, text:string):Token { - return new Token(index, TOKEN_TYPE_OPERATOR, 0, text); -} - -function newStringToken(index:int, text:string):Token { - return new Token(index, TOKEN_TYPE_STRING, 0, text); -} - -function newNumberToken(index:int, n:number):Token { - return new Token(index, TOKEN_TYPE_NUMBER, n, ""); -} - - -export var EOF:Token = new Token(-1, 0, 0, ""); - -export const $EOF = 0; -export const $TAB = 9; -export const $LF = 10; -export const $VTAB = 11; -export const $FF = 12; -export const $CR = 13; -export const $SPACE = 32; -export const $BANG = 33; -export const $DQ = 34; -export const $HASH = 35; -export const $$ = 36; -export const $PERCENT = 37; -export const $AMPERSAND = 38; -export const $SQ = 39; -export const $LPAREN = 40; -export const $RPAREN = 41; -export const $STAR = 42; -export const $PLUS = 43; -export const $COMMA = 44; -export const $MINUS = 45; -export const $PERIOD = 46; -export const $SLASH = 47; -export const $COLON = 58; -export const $SEMICOLON = 59; -export const $LT = 60; -export const $EQ = 61; -export const $GT = 62; -export const $QUESTION = 63; - -const $0 = 48; -const $9 = 57; - -const $A = 65, $E = 69, $Z = 90; - -export const $LBRACKET = 91; -export const $BACKSLASH = 92; -export const $RBRACKET = 93; -const $CARET = 94; -const $_ = 95; - -const $a = 97, $e = 101, $f = 102, $n = 110, $r = 114, $t = 116, $u = 117, $v = 118, $z = 122; - -export const $LBRACE = 123; -export const $BAR = 124; -export const $RBRACE = 125; -const $NBSP = 160; - - -export class ScannerError extends BaseException { - message:string; - constructor(message) { - super(); - this.message = message; - } - - toString() { - return this.message; - } -} - -class _Scanner { - input:string; - length:int; - peek:int; - index:int; - - constructor(input:string) { - this.input = input; - this.length = input.length; - this.peek = 0; - this.index = -1; - this.advance(); - } - - advance() { - this.peek = ++this.index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, this.index); - } - - scanToken():Token { - var input = this.input, - length = this.length, - peek = this.peek, - index = this.index; - - // Skip whitespace. - while (peek <= $SPACE) { - if (++index >= length) { - peek = $EOF; - break; - } else { - peek = StringWrapper.charCodeAt(input, index); - } - } - - this.peek = peek; - this.index = index; - - if (index >= length) { - return null; - } - - // Handle identifiers and numbers. - if (isIdentifierStart(peek)) return this.scanIdentifier(); - if (isDigit(peek)) return this.scanNumber(index); - - var start:int = index; - switch (peek) { - case $PERIOD: - this.advance(); - return isDigit(this.peek) ? this.scanNumber(start) : - newCharacterToken(start, $PERIOD); - case $LPAREN: case $RPAREN: - case $LBRACE: case $RBRACE: - case $LBRACKET: case $RBRACKET: - case $COMMA: - case $COLON: - case $SEMICOLON: - return this.scanCharacter(start, peek); - case $SQ: - case $DQ: - return this.scanString(); - case $HASH: - return this.scanOperator(start, StringWrapper.fromCharCode(peek)); - case $PLUS: - case $MINUS: - case $STAR: - case $SLASH: - case $PERCENT: - case $CARET: - case $QUESTION: - return this.scanOperator(start, StringWrapper.fromCharCode(peek)); - case $LT: - case $GT: - case $BANG: - case $EQ: - return this.scanComplexOperator(start, $EQ, StringWrapper.fromCharCode(peek), '='); - case $AMPERSAND: - return this.scanComplexOperator(start, $AMPERSAND, '&', '&'); - case $BAR: - return this.scanComplexOperator(start, $BAR, '|', '|'); - case $NBSP: - while (isWhitespace(this.peek)) this.advance(); - return this.scanToken(); - } - - this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`, 0); - return null; - } - - scanCharacter(start:int, code:int):Token { - assert(this.peek == code); - this.advance(); - return newCharacterToken(start, code); - } - - - scanOperator(start:int, str:string):Token { - assert(this.peek == StringWrapper.charCodeAt(str, 0)); - assert(SetWrapper.has(OPERATORS, str)); - this.advance(); - return newOperatorToken(start, str); - } - - scanComplexOperator(start:int, code:int, one:string, two:string):Token { - assert(this.peek == StringWrapper.charCodeAt(one, 0)); - this.advance(); - var str:string = one; - while (this.peek == code) { - this.advance(); - str += two; - } - assert(SetWrapper.has(OPERATORS, str)); - return newOperatorToken(start, str); - } - - scanIdentifier():Token { - assert(isIdentifierStart(this.peek)); - var start:int = this.index; - this.advance(); - while (isIdentifierPart(this.peek)) this.advance(); - var str:string = this.input.substring(start, this.index); - if (SetWrapper.has(KEYWORDS, str)) { - return newKeywordToken(start, str); - } else { - return newIdentifierToken(start, str); - } - } - - scanNumber(start:int):Token { - assert(isDigit(this.peek)); - var simple:boolean = (this.index === start); - this.advance(); // Skip initial digit. - while (true) { - if (isDigit(this.peek)) { - // Do nothing. - } else if (this.peek == $PERIOD) { - simple = false; - } else if (isExponentStart(this.peek)) { - this.advance(); - if (isExponentSign(this.peek)) this.advance(); - if (!isDigit(this.peek)) this.error('Invalid exponent', -1); - simple = false; - } else { - break; - } - this.advance(); - } - var str:string = this.input.substring(start, this.index); - // TODO - var value:number = simple ? NumberWrapper.parseIntAutoRadix(str) : NumberWrapper.parseFloat(str); - return newNumberToken(start, value); - } - - scanString():Token { - assert(this.peek == $SQ || this.peek == $DQ); - var start:int = this.index; - var quote:int = this.peek; - this.advance(); // Skip initial quote. - - var buffer:StringJoiner; - var marker:int = this.index; - var input:string = this.input; - - while (this.peek != quote) { - if (this.peek == $BACKSLASH) { - if (buffer == null) buffer = new StringJoiner(); - buffer.add(input.substring(marker, this.index)); - this.advance(); - var unescapedCode:int; - if (this.peek == $u) { - // 4 character hex code for unicode character. - var hex:string = input.substring(this.index + 1, this.index + 5); - try { - unescapedCode = NumberWrapper.parseInt(hex, 16); - } catch (e) { - this.error(`Invalid unicode escape [\\u${hex}]`, 0); - } - for (var i:int = 0; i < 5; i++) { - this.advance(); - } - } else { - unescapedCode = unescape(this.peek); - this.advance(); - } - buffer.add(StringWrapper.fromCharCode(unescapedCode)); - marker = this.index; - } else if (this.peek == $EOF) { - this.error('Unterminated quote', 0); - } else { - this.advance(); - } - } - - var last:string = input.substring(marker, this.index); - this.advance(); // Skip terminating quote. - - // Compute the unescaped string value. - var unescaped:string = last; - if (buffer != null) { - buffer.add(last); - unescaped = buffer.toString(); - } - return newStringToken(start, unescaped); - } - - error(message:string, offset:int) { - var position:int = this.index + offset; - throw new ScannerError(`Lexer Error: ${message} at column ${position} in expression [${this.input}]`); - } -} - -function isWhitespace(code:int):boolean { - return (code >= $TAB && code <= $SPACE) || (code == $NBSP); -} - -function isIdentifierStart(code:int):boolean { - return ($a <= code && code <= $z) || - ($A <= code && code <= $Z) || - (code == $_) || - (code == $$); -} - -function isIdentifierPart(code:int):boolean { - return ($a <= code && code <= $z) || - ($A <= code && code <= $Z) || - ($0 <= code && code <= $9) || - (code == $_) || - (code == $$); -} - -function isDigit(code:int):boolean { - return $0 <= code && code <= $9; -} - -function isExponentStart(code:int):boolean { - return code == $e || code == $E; -} - -function isExponentSign(code:int):boolean { - return code == $MINUS || code == $PLUS; -} - -function unescape(code:int):int { - switch(code) { - case $n: return $LF; - case $f: return $FF; - case $r: return $CR; - case $t: return $TAB; - case $v: return $VTAB; - default: return code; - } -} - -var OPERATORS = SetWrapper.createFromList([ - '+', - '-', - '*', - '/', - '%', - '^', - '=', - '==', - '!=', - '===', - '!==', - '<', - '>', - '<=', - '>=', - '&&', - '||', - '&', - '|', - '!', - '?', - '#' -]); - - -var KEYWORDS = SetWrapper.createFromList([ - 'var', - 'null', - 'undefined', - 'true', - 'false' -]); diff --git a/modules/angular2/src/change_detection/parser/lexer.ts b/modules/angular2/src/change_detection/parser/lexer.ts new file mode 100644 index 0000000000..71770876c2 --- /dev/null +++ b/modules/angular2/src/change_detection/parser/lexer.ts @@ -0,0 +1,452 @@ +import {Injectable} from 'angular2/src/di/decorators'; +import {List, ListWrapper, SetWrapper} from "angular2/src/facade/collection"; +import { + int, + NumberWrapper, + StringJoiner, + StringWrapper, + BaseException +} from "angular2/src/facade/lang"; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export const TOKEN_TYPE_CHARACTER = 1; +export const TOKEN_TYPE_IDENTIFIER = 2; +export const TOKEN_TYPE_KEYWORD = 3; +export const TOKEN_TYPE_STRING = 4; +export const TOKEN_TYPE_OPERATOR = 5; +export const TOKEN_TYPE_NUMBER = 6; + +@Injectable() +export class Lexer { + tokenize(text: string): List { + var scanner = new _Scanner(text); + var tokens = []; + var token = scanner.scanToken(); + while (token != null) { + ListWrapper.push(tokens, token); + token = scanner.scanToken(); + } + return tokens; + } +} + +export class Token { + constructor(public index: int, public type: int, public numValue: number, + public strValue: string) {} + + isCharacter(code: int): boolean { + return (this.type == TOKEN_TYPE_CHARACTER && this.numValue == code); + } + + isNumber(): boolean { return (this.type == TOKEN_TYPE_NUMBER); } + + isString(): boolean { return (this.type == TOKEN_TYPE_STRING); } + + isOperator(operater: string): boolean { + return (this.type == TOKEN_TYPE_OPERATOR && this.strValue == operater); + } + + isIdentifier(): boolean { return (this.type == TOKEN_TYPE_IDENTIFIER); } + + isKeyword(): boolean { return (this.type == TOKEN_TYPE_KEYWORD); } + + isKeywordVar(): boolean { return (this.type == TOKEN_TYPE_KEYWORD && this.strValue == "var"); } + + isKeywordNull(): boolean { return (this.type == TOKEN_TYPE_KEYWORD && this.strValue == "null"); } + + isKeywordUndefined(): boolean { + return (this.type == TOKEN_TYPE_KEYWORD && this.strValue == "undefined"); + } + + isKeywordTrue(): boolean { return (this.type == TOKEN_TYPE_KEYWORD && this.strValue == "true"); } + + isKeywordFalse(): boolean { + return (this.type == TOKEN_TYPE_KEYWORD && this.strValue == "false"); + } + + toNumber(): number { + // -1 instead of NULL ok? + return (this.type == TOKEN_TYPE_NUMBER) ? this.numValue : -1; + } + + toString(): string { + var t: int = this.type; + if (t >= TOKEN_TYPE_CHARACTER && t <= TOKEN_TYPE_STRING) { + return this.strValue; + } else if (t == TOKEN_TYPE_NUMBER) { + return this.numValue.toString(); + } else { + return null; + } + } +} + +function newCharacterToken(index: int, code: int): Token { + return new Token(index, TOKEN_TYPE_CHARACTER, code, StringWrapper.fromCharCode(code)); +} + +function newIdentifierToken(index: int, text: string): Token { + return new Token(index, TOKEN_TYPE_IDENTIFIER, 0, text); +} + +function newKeywordToken(index: int, text: string): Token { + return new Token(index, TOKEN_TYPE_KEYWORD, 0, text); +} + +function newOperatorToken(index: int, text: string): Token { + return new Token(index, TOKEN_TYPE_OPERATOR, 0, text); +} + +function newStringToken(index: int, text: string): Token { + return new Token(index, TOKEN_TYPE_STRING, 0, text); +} + +function newNumberToken(index: int, n: number): Token { + return new Token(index, TOKEN_TYPE_NUMBER, n, ""); +} + + +export var EOF: Token = new Token(-1, 0, 0, ""); + +export const $EOF = 0; +export const $TAB = 9; +export const $LF = 10; +export const $VTAB = 11; +export const $FF = 12; +export const $CR = 13; +export const $SPACE = 32; +export const $BANG = 33; +export const $DQ = 34; +export const $HASH = 35; +export const $$ = 36; +export const $PERCENT = 37; +export const $AMPERSAND = 38; +export const $SQ = 39; +export const $LPAREN = 40; +export const $RPAREN = 41; +export const $STAR = 42; +export const $PLUS = 43; +export const $COMMA = 44; +export const $MINUS = 45; +export const $PERIOD = 46; +export const $SLASH = 47; +export const $COLON = 58; +export const $SEMICOLON = 59; +export const $LT = 60; +export const $EQ = 61; +export const $GT = 62; +export const $QUESTION = 63; + +const $0 = 48; +const $9 = 57; + +const $A = 65, $E = 69, $Z = 90; + +export const $LBRACKET = 91; +export const $BACKSLASH = 92; +export const $RBRACKET = 93; +const $CARET = 94; +const $_ = 95; + +const $a = 97, $e = 101, $f = 102, $n = 110, $r = 114, $t = 116, $u = 117, $v = 118, $z = 122; + +export const $LBRACE = 123; +export const $BAR = 124; +export const $RBRACE = 125; +const $NBSP = 160; + + +export class ScannerError extends BaseException { + message: string; + constructor(message) { + super(); + this.message = message; + } + + toString() { return this.message; } +} + +class _Scanner { + length: int; + peek: int; + index: int; + + constructor(public input: string) { + this.length = input.length; + this.peek = 0; + this.index = -1; + this.advance(); + } + + advance() { + this.peek = + ++this.index >= this.length ? $EOF : StringWrapper.charCodeAt(this.input, this.index); + } + + scanToken(): Token { + var input = this.input, length = this.length, peek = this.peek, index = this.index; + + // Skip whitespace. + while (peek <= $SPACE) { + if (++index >= length) { + peek = $EOF; + break; + } else { + peek = StringWrapper.charCodeAt(input, index); + } + } + + this.peek = peek; + this.index = index; + + if (index >= length) { + return null; + } + + // Handle identifiers and numbers. + if (isIdentifierStart(peek)) return this.scanIdentifier(); + if (isDigit(peek)) return this.scanNumber(index); + + var start: int = index; + switch (peek) { + case $PERIOD: + this.advance(); + return isDigit(this.peek) ? this.scanNumber(start) : newCharacterToken(start, $PERIOD); + case $LPAREN: + case $RPAREN: + case $LBRACE: + case $RBRACE: + case $LBRACKET: + case $RBRACKET: + case $COMMA: + case $COLON: + case $SEMICOLON: + return this.scanCharacter(start, peek); + case $SQ: + case $DQ: + return this.scanString(); + case $HASH: + return this.scanOperator(start, StringWrapper.fromCharCode(peek)); + case $PLUS: + case $MINUS: + case $STAR: + case $SLASH: + case $PERCENT: + case $CARET: + case $QUESTION: + return this.scanOperator(start, StringWrapper.fromCharCode(peek)); + case $LT: + case $GT: + case $BANG: + case $EQ: + return this.scanComplexOperator(start, $EQ, StringWrapper.fromCharCode(peek), '='); + case $AMPERSAND: + return this.scanComplexOperator(start, $AMPERSAND, '&', '&'); + case $BAR: + return this.scanComplexOperator(start, $BAR, '|', '|'); + case $NBSP: + while (isWhitespace(this.peek)) this.advance(); + return this.scanToken(); + } + + this.error(`Unexpected character [${StringWrapper.fromCharCode(peek)}]`, 0); + return null; + } + + scanCharacter(start: int, code: int): Token { + assert(this.peek == code); + this.advance(); + return newCharacterToken(start, code); + } + + + scanOperator(start: int, str: string): Token { + assert(this.peek == StringWrapper.charCodeAt(str, 0)); + assert(SetWrapper.has(OPERATORS, str)); + this.advance(); + return newOperatorToken(start, str); + } + + scanComplexOperator(start: int, code: int, one: string, two: string): Token { + assert(this.peek == StringWrapper.charCodeAt(one, 0)); + this.advance(); + var str: string = one; + while (this.peek == code) { + this.advance(); + str += two; + } + assert(SetWrapper.has(OPERATORS, str)); + return newOperatorToken(start, str); + } + + scanIdentifier(): Token { + assert(isIdentifierStart(this.peek)); + var start: int = this.index; + this.advance(); + while (isIdentifierPart(this.peek)) this.advance(); + var str: string = this.input.substring(start, this.index); + if (SetWrapper.has(KEYWORDS, str)) { + return newKeywordToken(start, str); + } else { + return newIdentifierToken(start, str); + } + } + + scanNumber(start: int): Token { + assert(isDigit(this.peek)); + var simple: boolean = (this.index === start); + this.advance(); // Skip initial digit. + while (true) { + if (isDigit(this.peek)) { + // Do nothing. + } else if (this.peek == $PERIOD) { + simple = false; + } else if (isExponentStart(this.peek)) { + this.advance(); + if (isExponentSign(this.peek)) this.advance(); + if (!isDigit(this.peek)) this.error('Invalid exponent', -1); + simple = false; + } else { + break; + } + this.advance(); + } + var str: string = this.input.substring(start, this.index); + // TODO + var value: number = + simple ? NumberWrapper.parseIntAutoRadix(str) : NumberWrapper.parseFloat(str); + return newNumberToken(start, value); + } + + scanString(): Token { + assert(this.peek == $SQ || this.peek == $DQ); + var start: int = this.index; + var quote: int = this.peek; + this.advance(); // Skip initial quote. + + var buffer: StringJoiner; + var marker: int = this.index; + var input: string = this.input; + + while (this.peek != quote) { + if (this.peek == $BACKSLASH) { + if (buffer == null) buffer = new StringJoiner(); + buffer.add(input.substring(marker, this.index)); + this.advance(); + var unescapedCode: int; + if (this.peek == $u) { + // 4 character hex code for unicode character. + var hex: string = input.substring(this.index + 1, this.index + 5); + try { + unescapedCode = NumberWrapper.parseInt(hex, 16); + } catch (e) { + this.error(`Invalid unicode escape [\\u${hex}]`, 0); + } + for (var i: int = 0; i < 5; i++) { + this.advance(); + } + } else { + unescapedCode = unescape(this.peek); + this.advance(); + } + buffer.add(StringWrapper.fromCharCode(unescapedCode)); + marker = this.index; + } else if (this.peek == $EOF) { + this.error('Unterminated quote', 0); + } else { + this.advance(); + } + } + + var last: string = input.substring(marker, this.index); + this.advance(); // Skip terminating quote. + + // Compute the unescaped string value. + var unescaped: string = last; + if (buffer != null) { + buffer.add(last); + unescaped = buffer.toString(); + } + return newStringToken(start, unescaped); + } + + error(message: string, offset: int) { + var position: int = this.index + offset; + throw new ScannerError( + `Lexer Error: ${message} at column ${position} in expression [${this.input}]`); + } +} + +function isWhitespace(code: int): boolean { + return (code >= $TAB && code <= $SPACE) || (code == $NBSP); +} + +function isIdentifierStart(code: int): boolean { + return ($a <= code && code <= $z) || ($A <= code && code <= $Z) || (code == $_) || (code == $$); +} + +function isIdentifierPart(code: int): boolean { + return ($a <= code && code <= $z) || ($A <= code && code <= $Z) || ($0 <= code && code <= $9) || + (code == $_) || (code == $$); +} + +function isDigit(code: int): boolean { + return $0 <= code && code <= $9; +} + +function isExponentStart(code: int): boolean { + return code == $e || code == $E; +} + +function isExponentSign(code: int): boolean { + return code == $MINUS || code == $PLUS; +} + +function unescape(code: int): int { + switch (code) { + case $n: + return $LF; + case $f: + return $FF; + case $r: + return $CR; + case $t: + return $TAB; + case $v: + return $VTAB; + default: + return code; + } +} + +var OPERATORS = SetWrapper.createFromList([ + '+', + '-', + '*', + '/', + '%', + '^', + '=', + '==', + '!=', + '===', + '!==', + '<', + '>', + '<=', + '>=', + '&&', + '||', + '&', + '|', + '!', + '?', + '#' +]); + + +var KEYWORDS = SetWrapper.createFromList(['var', 'null', 'undefined', 'true', 'false']); diff --git a/modules/angular2/src/change_detection/parser/locals.js b/modules/angular2/src/change_detection/parser/locals.ts similarity index 70% rename from modules/angular2/src/change_detection/parser/locals.js rename to modules/angular2/src/change_detection/parser/locals.ts index 7911213030..d2a9771200 100644 --- a/modules/angular2/src/change_detection/parser/locals.js +++ b/modules/angular2/src/change_detection/parser/locals.ts @@ -1,16 +1,15 @@ import {isPresent, BaseException} from 'angular2/src/facade/lang'; import {ListWrapper, MapWrapper} from 'angular2/src/facade/collection'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + export class Locals { - parent:Locals; - current:Map; + constructor(public parent: Locals, public current: Map) {} - constructor(parent:Locals, current:Map) { - this.parent = parent; - this.current = current; - } - - contains(name:string):boolean { + contains(name: string): boolean { if (MapWrapper.contains(this.current, name)) { return true; } @@ -22,7 +21,7 @@ export class Locals { return false; } - get(name:string) { + get(name: string) { if (MapWrapper.contains(this.current, name)) { return MapWrapper.get(this.current, name); } @@ -34,7 +33,7 @@ export class Locals { throw new BaseException(`Cannot find '${name}'`); } - set(name:string, value):void { + set(name: string, value): void { // TODO(rado): consider removing this check if we can guarantee this is not // exposed to the public API. // TODO: vsavkin maybe it should check only the local map @@ -45,7 +44,5 @@ export class Locals { } } - clearValues():void { - MapWrapper.clearValues(this.current); - } + clearValues(): void { MapWrapper.clearValues(this.current); } } \ No newline at end of file diff --git a/modules/angular2/src/change_detection/parser/parser.js b/modules/angular2/src/change_detection/parser/parser.ts similarity index 82% rename from modules/angular2/src/change_detection/parser/parser.js rename to modules/angular2/src/change_detection/parser/parser.ts index 41693f78a8..2027a79f78 100644 --- a/modules/angular2/src/change_detection/parser/parser.js +++ b/modules/angular2/src/change_detection/parser/parser.ts @@ -1,8 +1,28 @@ -import {Injectable} from 'angular2/src/di/annotations_impl'; -import {int, isBlank, isPresent, BaseException, StringWrapper, RegExpWrapper} from 'angular2/src/facade/lang'; +import {Injectable} from 'angular2/src/di/decorators'; +import { + int, + isBlank, + isPresent, + BaseException, + StringWrapper, + RegExpWrapper +} from 'angular2/src/facade/lang'; import {ListWrapper, List} from 'angular2/src/facade/collection'; -import {Lexer, EOF, Token, $PERIOD, $COLON, $SEMICOLON, $LBRACKET, $RBRACKET, - $COMMA, $LBRACE, $RBRACE, $LPAREN, $RPAREN} from './lexer'; +import { + Lexer, + EOF, + Token, + $PERIOD, + $COLON, + $SEMICOLON, + $LBRACKET, + $RBRACKET, + $COMMA, + $LBRACE, + $RBRACE, + $LPAREN, + $RPAREN +} from './lexer'; import {reflector, Reflector} from 'angular2/src/reflection/reflection'; import { AST, @@ -10,7 +30,6 @@ import { ImplicitReceiver, AccessMember, LiteralPrimitive, - Expression, Binary, PrefixNot, Conditional, @@ -23,10 +42,15 @@ import { Interpolation, MethodCall, FunctionCall, - TemplateBindings, TemplateBinding, ASTWithSource - } from './ast'; +} from './ast'; + + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; var _implicitReceiver = new ImplicitReceiver(); // TODO(tbosch): Cannot make this const/final right now because of the transpiler... @@ -34,40 +58,40 @@ var INTERPOLATION_REGEXP = RegExpWrapper.create('\\{\\{(.*?)\\}\\}'); @Injectable() export class Parser { - _lexer:Lexer; - _reflector:Reflector; - constructor(lexer:Lexer, providedReflector:Reflector = null){ + _lexer: Lexer; + _reflector: Reflector; + constructor(lexer: Lexer, providedReflector: Reflector = null) { this._lexer = lexer; this._reflector = isPresent(providedReflector) ? providedReflector : reflector; } - parseAction(input:string, location:any):ASTWithSource { + parseAction(input: string, location: any): ASTWithSource { var tokens = this._lexer.tokenize(input); var ast = new _ParseAST(input, location, tokens, this._reflector, true).parseChain(); return new ASTWithSource(ast, input, location); } - parseBinding(input:string, location:any):ASTWithSource { + parseBinding(input: string, location: any): ASTWithSource { var tokens = this._lexer.tokenize(input); var ast = new _ParseAST(input, location, tokens, this._reflector, false).parseChain(); return new ASTWithSource(ast, input, location); } - addPipes(bindingAst:ASTWithSource, pipes:List):ASTWithSource { + addPipes(bindingAst: ASTWithSource, pipes: List): ASTWithSource { if (ListWrapper.isEmpty(pipes)) return bindingAst; - var res = ListWrapper.reduce(pipes, - (result, currentPipeName) => new Pipe(result, currentPipeName, [], false), - bindingAst.ast); + var res: AST = ListWrapper.reduce( + pipes, (result, currentPipeName) => new Pipe(result, currentPipeName, [], false), + bindingAst.ast); return new ASTWithSource(res, bindingAst.source, bindingAst.location); } - parseTemplateBindings(input:string, location:any):List { + parseTemplateBindings(input: string, location: any): List { var tokens = this._lexer.tokenize(input); return new _ParseAST(input, location, tokens, this._reflector, false).parseTemplateBindings(); } - parseInterpolation(input:string, location:any):ASTWithSource { + parseInterpolation(input: string, location: any): ASTWithSource { var parts = StringWrapper.split(input, INTERPOLATION_REGEXP); if (parts.length <= 1) { return null; @@ -75,9 +99,9 @@ export class Parser { var strings = []; var expressions = []; - for (var i=0; i; - reflector:Reflector; - parseAction:boolean; - index:int; - constructor(input:string, location:any, tokens:List, reflector:Reflector, parseAction:boolean) { - this.input = input; - this.location = location; - this.tokens = tokens; + index: int; + constructor(public input: string, public location: any, public tokens: List, + public reflector: Reflector, public parseAction: boolean) { this.index = 0; - this.reflector = reflector; - this.parseAction = parseAction; } - peek(offset:int):Token { + peek(offset: int): Token { var i = this.index + offset; return i < this.tokens.length ? this.tokens[i] : EOF; } - get next():Token { - return this.peek(0); - } + get next(): Token { return this.peek(0); } - get inputIndex():int { + get inputIndex(): int { return (this.index < this.tokens.length) ? this.next.index : this.input.length; } - advance() { - this.index ++; - } + advance() { this.index++; } - optionalCharacter(code:int):boolean { + optionalCharacter(code: int): boolean { if (this.next.isCharacter(code)) { this.advance(); return true; @@ -137,7 +147,7 @@ class _ParseAST { } } - optionalKeywordVar():boolean { + optionalKeywordVar(): boolean { if (this.peekKeywordVar()) { this.advance(); return true; @@ -146,17 +156,15 @@ class _ParseAST { } } - peekKeywordVar():boolean { - return this.next.isKeywordVar() || this.next.isOperator('#'); - } + peekKeywordVar(): boolean { return this.next.isKeywordVar() || this.next.isOperator('#'); } - expectCharacter(code:int) { + expectCharacter(code: int) { if (this.optionalCharacter(code)) return; this.error(`Missing expected ${StringWrapper.fromCharCode(code)}`); } - optionalOperator(op:string):boolean { + optionalOperator(op: string): boolean { if (this.next.isOperator(op)) { this.advance(); return true; @@ -165,12 +173,12 @@ class _ParseAST { } } - expectOperator(operator:string) { + expectOperator(operator: string) { if (this.optionalOperator(operator)) return; this.error(`Missing expected operator ${operator}`); } - expectIdentifierOrKeyword():string { + expectIdentifierOrKeyword(): string { var n = this.next; if (!n.isIdentifier() && !n.isKeyword()) { this.error(`Unexpected token ${n}, expected identifier or keyword`) @@ -179,7 +187,7 @@ class _ParseAST { return n.toString(); } - expectIdentifierOrKeywordOrString():string { + expectIdentifierOrKeywordOrString(): string { var n = this.next; if (!n.isIdentifier() && !n.isKeyword() && !n.isString()) { this.error(`Unexpected token ${n}, expected identifier, keyword, or string`) @@ -188,17 +196,18 @@ class _ParseAST { return n.toString(); } - parseChain():AST { + parseChain(): AST { var exprs = []; while (this.index < this.tokens.length) { var expr = this.parsePipe(); ListWrapper.push(exprs, expr); if (this.optionalCharacter($SEMICOLON)) { - if (! this.parseAction) { + if (!this.parseAction) { this.error("Binding expression cannot contain chained expression"); } - while (this.optionalCharacter($SEMICOLON)){} //read all semicolons + while (this.optionalCharacter($SEMICOLON)) { + } // read all semicolons } else if (this.index < this.tokens.length) { this.error(`Unexpected token '${this.next}'`); } @@ -353,7 +362,7 @@ class _ParseAST { } } - parseCallChain():AST { + parseCallChain(): AST { var result = this.parsePrimary(); while (true) { if (this.optionalCharacter($PERIOD)) { @@ -410,9 +419,9 @@ class _ParseAST { return new LiteralPrimitive(value); } else if (this.next.isString()) { - var value = this.next.toString(); + var literalValue = this.next.toString(); this.advance(); - return new LiteralPrimitive(value); + return new LiteralPrimitive(literalValue); } else if (this.index >= this.tokens.length) { this.error(`Unexpected end of expression: ${this.input}`); @@ -422,7 +431,7 @@ class _ParseAST { } } - parseExpressionList(terminator:int):List { + parseExpressionList(terminator: int): List { var result = []; if (!this.next.isCharacter(terminator)) { do { @@ -448,7 +457,7 @@ class _ParseAST { return new LiteralMap(keys, values); } - parseAccessMemberOrMethodCall(receiver):AST { + parseAccessMemberOrMethodCall(receiver): AST { var id = this.expectIdentifierOrKeyword(); if (this.optionalCharacter($LPAREN)) { @@ -471,7 +480,7 @@ class _ParseAST { } parseInlinedPipe(result) { - do { + do { if (this.parseAction) { this.error("Cannot have a pipe in an action expression"); } @@ -481,7 +490,7 @@ class _ParseAST { ListWrapper.push(args, this.parseExpression()); } result = new Pipe(result, name, args, true); - } while(this.optionalOperator("|")); + } while (this.optionalOperator("|")); return result; } @@ -515,7 +524,7 @@ class _ParseAST { parseTemplateBindings() { var bindings = []; while (this.index < this.tokens.length) { - var keyIsVar:boolean = this.optionalKeywordVar(); + var keyIsVar: boolean = this.optionalKeywordVar(); var key = this.expectTemplateBindingKey(); this.optionalCharacter($COLON); var name = null; @@ -542,13 +551,13 @@ class _ParseAST { return bindings; } - error(message:string, index:int = null) { + error(message: string, index: int = null) { if (isBlank(index)) index = this.index; - var location = (index < this.tokens.length) - ? `at column ${this.tokens[index].index + 1} in` - : `at the end of the expression`; + var location = (index < this.tokens.length) ? `at column ${this.tokens[index].index + 1} in` : + `at the end of the expression`; - throw new BaseException(`Parser Error: ${message} ${location} [${this.input}] in ${this.location}`); + throw new BaseException( + `Parser Error: ${message} ${location} [${this.input}] in ${this.location}`); } } diff --git a/modules/angular2/src/change_detection/pipes/async_pipe.js b/modules/angular2/src/change_detection/pipes/async_pipe.ts similarity index 64% rename from modules/angular2/src/change_detection/pipes/async_pipe.js rename to modules/angular2/src/change_detection/pipes/async_pipe.ts index 539aa7ddec..518ae8988b 100644 --- a/modules/angular2/src/change_detection/pipes/async_pipe.js +++ b/modules/angular2/src/change_detection/pipes/async_pipe.ts @@ -3,13 +3,21 @@ import {isBlank, isPresent, CONST} from 'angular2/src/facade/lang'; import {Pipe, WrappedValue, PipeFactory} from './pipe'; import {ChangeDetectorRef} from '../change_detector_ref'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + + /** * Implements async bindings to Observable. * * # Example * - * In this example we bind the description observable to the DOM. The async pipe will convert an observable to the - * latest value it emitted. It will also request a change detection check when a new value is emitted. + * In this example we bind the description observable to the DOM. The async pipe will convert an + *observable to the + * latest value it emitted. It will also request a change detection check when a new value is + *emitted. * * ``` * @Component({ @@ -28,15 +36,15 @@ import {ChangeDetectorRef} from '../change_detector_ref'; * @exportedAs angular2/pipes */ export class AsyncPipe extends Pipe { - _ref:ChangeDetectorRef; + _ref: ChangeDetectorRef; - _latestValue:Object; - _latestReturnedValue:Object; + _latestValue: Object; + _latestReturnedValue: Object; - _subscription:Object; - _observable:Observable; + _subscription: Object; + _observable: Observable; - constructor(ref:ChangeDetectorRef) { + constructor(ref: ChangeDetectorRef) { super(); this._ref = ref; this._latestValue = null; @@ -45,17 +53,15 @@ export class AsyncPipe extends Pipe { this._observable = null; } - supports(obs):boolean { - return ObservableWrapper.isObservable(obs); - } + supports(obs): boolean { return ObservableWrapper.isObservable(obs); } - onDestroy():void { + onDestroy(): void { if (isPresent(this._subscription)) { this._dispose(); } } - transform(obs:Observable):any { + transform(obs: Observable): any { if (isBlank(this._subscription)) { this._subscribe(obs); return null; @@ -74,15 +80,13 @@ export class AsyncPipe extends Pipe { } } - _subscribe(obs:Observable):void { + _subscribe(obs: Observable): void { this._observable = obs; - this._subscription = ObservableWrapper.subscribe(obs, - value => this._updateLatestValue(value), - e => {throw e;} - ); + this._subscription = ObservableWrapper.subscribe(obs, value => {this._updateLatestValue(value)}, + e => { throw e; }); } - _dispose():void { + _dispose(): void { ObservableWrapper.dispose(this._subscription); this._latestValue = null; this._latestReturnedValue = null; @@ -90,7 +94,7 @@ export class AsyncPipe extends Pipe { this._observable = null; } - _updateLatestValue(value:Object) { + _updateLatestValue(value: Object) { this._latestValue = value; this._ref.requestCheck(); } @@ -101,17 +105,11 @@ export class AsyncPipe extends Pipe { * * @exportedAs angular2/pipes */ +@CONST() export class AsyncPipeFactory extends PipeFactory { - @CONST() - constructor() { - super(); - } + constructor() { super(); } - supports(obs):boolean { - return ObservableWrapper.isObservable(obs); - } + supports(obs): boolean { return ObservableWrapper.isObservable(obs); } - create(cdRef):Pipe { - return new AsyncPipe(cdRef); - } + create(cdRef): Pipe { return new AsyncPipe(cdRef); } } \ No newline at end of file diff --git a/modules/angular2/src/change_detection/pipes/iterable_changes.js b/modules/angular2/src/change_detection/pipes/iterable_changes.ts similarity index 71% rename from modules/angular2/src/change_detection/pipes/iterable_changes.js rename to modules/angular2/src/change_detection/pipes/iterable_changes.ts index 6f109f858f..9433b691d4 100644 --- a/modules/angular2/src/change_detection/pipes/iterable_changes.js +++ b/modules/angular2/src/change_detection/pipes/iterable_changes.ts @@ -17,38 +17,37 @@ import { import {WrappedValue, Pipe, PipeFactory} from './pipe'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +@CONST() export class IterableChangesFactory extends PipeFactory { - @CONST() - constructor() { - super(); - } + constructor() { super(); } - supports(obj):boolean { - return IterableChanges.supportsObj(obj); - } + supports(obj): boolean { return IterableChanges.supportsObj(obj); } - create(cdRef):Pipe { - return new IterableChanges(); - } + create(cdRef): Pipe { return new IterableChanges(); } } /** * @exportedAs angular2/pipes */ export class IterableChanges extends Pipe { - _collection; - _length:int; - _linkedRecords:_DuplicateMap; - _unlinkedRecords:_DuplicateMap; - _previousItHead:CollectionChangeRecord; - _itHead:CollectionChangeRecord; - _itTail:CollectionChangeRecord; - _additionsHead:CollectionChangeRecord; - _additionsTail:CollectionChangeRecord; - _movesHead:CollectionChangeRecord; - _movesTail:CollectionChangeRecord; - _removalsHead:CollectionChangeRecord; - _removalsTail:CollectionChangeRecord; + private _collection; + private _length: int; + private _linkedRecords: _DuplicateMap; + private _unlinkedRecords: _DuplicateMap; + private _previousItHead: CollectionChangeRecord; + private _itHead: CollectionChangeRecord; + private _itTail: CollectionChangeRecord; + private _additionsHead: CollectionChangeRecord; + private _additionsTail: CollectionChangeRecord; + private _movesHead: CollectionChangeRecord; + private _movesTail: CollectionChangeRecord; + private _removalsHead: CollectionChangeRecord; + private _removalsTail: CollectionChangeRecord; constructor() { super(); @@ -70,58 +69,50 @@ export class IterableChanges extends Pipe { this._removalsTail = null; } - static supportsObj(obj):boolean { - return isListLikeIterable(obj); - } + static supportsObj(obj): boolean { return isListLikeIterable(obj); } - supports(obj):boolean { - return IterableChanges.supportsObj(obj); - } + supports(obj): boolean { return IterableChanges.supportsObj(obj); } - get collection() { - return this._collection; - } + get collection() { return this._collection; } - get length():int { - return this._length; - } + get length(): int { return this._length; } - forEachItem(fn:Function) { - var record:CollectionChangeRecord; + forEachItem(fn: Function) { + var record: CollectionChangeRecord; for (record = this._itHead; record !== null; record = record._next) { fn(record); } } - forEachPreviousItem(fn:Function) { - var record:CollectionChangeRecord; + forEachPreviousItem(fn: Function) { + var record: CollectionChangeRecord; for (record = this._previousItHead; record !== null; record = record._nextPrevious) { fn(record); } } - forEachAddedItem(fn:Function){ - var record:CollectionChangeRecord; + forEachAddedItem(fn: Function) { + var record: CollectionChangeRecord; for (record = this._additionsHead; record !== null; record = record._nextAdded) { fn(record); } } - forEachMovedItem(fn:Function) { - var record:CollectionChangeRecord; + forEachMovedItem(fn: Function) { + var record: CollectionChangeRecord; for (record = this._movesHead; record !== null; record = record._nextMoved) { fn(record); } } - forEachRemovedItem(fn:Function){ - var record:CollectionChangeRecord; + forEachRemovedItem(fn: Function) { + var record: CollectionChangeRecord; for (record = this._removalsHead; record !== null; record = record._nextRemoved) { fn(record); } } - transform(collection){ + transform(collection): any { if (this.check(collection)) { return WrappedValue.wrap(this); } else { @@ -130,12 +121,12 @@ export class IterableChanges extends Pipe { } // todo(vicb): optim for UnmodifiableListView (frozen arrays) - check(collection):boolean { + check(collection): boolean { this._reset(); - var record:CollectionChangeRecord = this._itHead; - var mayBeDirty:boolean = false; - var index:int; + var record: CollectionChangeRecord = this._itHead; + var mayBeDirty: boolean = false; + var index: int; var item; if (ListWrapper.isList(collection)) { @@ -175,10 +166,8 @@ export class IterableChanges extends Pipe { } // CollectionChanges is considered dirty if it has any additions, moves or removals. - get isDirty():boolean { - return this._additionsHead !== null || - this._movesHead !== null || - this._removalsHead !== null; + get isDirty(): boolean { + return this._additionsHead !== null || this._movesHead !== null || this._removalsHead !== null; } /** @@ -189,8 +178,8 @@ export class IterableChanges extends Pipe { */ _reset() { if (this.isDirty) { - var record:CollectionChangeRecord; - var nextRecord:CollectionChangeRecord; + var record: CollectionChangeRecord; + var nextRecord: CollectionChangeRecord; for (record = this._previousItHead = this._itHead; record !== null; record = record._next) { record._nextPrevious = record._next; @@ -221,9 +210,9 @@ export class IterableChanges extends Pipe { * - `item` is the current item in the collection * - `index` is the position of the item in the collection */ - _mismatch(record:CollectionChangeRecord, item, index:int):CollectionChangeRecord { + _mismatch(record: CollectionChangeRecord, item, index: int): CollectionChangeRecord { // The previous record after which we will append the current one. - var previousRecord:CollectionChangeRecord; + var previousRecord: CollectionChangeRecord; if (record === null) { previousRecord = this._itTail; @@ -277,9 +266,9 @@ export class IterableChanges extends Pipe { * better way to think of it is as insert of 'b' rather then switch 'a' with 'b' and then add 'a' * at the end. */ - _verifyReinsertion(record:CollectionChangeRecord, item, index:int):CollectionChangeRecord { - var reinsertRecord:CollectionChangeRecord = this._unlinkedRecords === null ? - null : this._unlinkedRecords.get(item); + _verifyReinsertion(record: CollectionChangeRecord, item, index: int): CollectionChangeRecord { + var reinsertRecord: CollectionChangeRecord = + this._unlinkedRecords === null ? null : this._unlinkedRecords.get(item); if (reinsertRecord !== null) { record = this._reinsertAfter(reinsertRecord, record._prev, index); } else if (record.currentIndex != index) { @@ -294,10 +283,10 @@ export class IterableChanges extends Pipe { * * - `record` The first excess {@link CollectionChangeRecord}. */ - _truncate(record:CollectionChangeRecord) { + _truncate(record: CollectionChangeRecord) { // Anything after that needs to be removed; while (record !== null) { - var nextRecord:CollectionChangeRecord = record._next; + var nextRecord: CollectionChangeRecord = record._next; this._addToRemovals(this._unlink(record)); record = nextRecord; } @@ -319,8 +308,8 @@ export class IterableChanges extends Pipe { } } - _reinsertAfter(record:CollectionChangeRecord, prevRecord:CollectionChangeRecord, - index:int):CollectionChangeRecord { + _reinsertAfter(record: CollectionChangeRecord, prevRecord: CollectionChangeRecord, + index: int): CollectionChangeRecord { if (this._unlinkedRecords !== null) { this._unlinkedRecords.remove(record); } @@ -343,42 +332,42 @@ export class IterableChanges extends Pipe { return record; } - _moveAfter(record:CollectionChangeRecord, prevRecord:CollectionChangeRecord, - index:int):CollectionChangeRecord { + _moveAfter(record: CollectionChangeRecord, prevRecord: CollectionChangeRecord, + index: int): CollectionChangeRecord { this._unlink(record); this._insertAfter(record, prevRecord, index); this._addToMoves(record, index); return record; } - _addAfter(record:CollectionChangeRecord, prevRecord:CollectionChangeRecord, - index:int):CollectionChangeRecord { + _addAfter(record: CollectionChangeRecord, prevRecord: CollectionChangeRecord, + index: int): CollectionChangeRecord { this._insertAfter(record, prevRecord, index); if (this._additionsTail === null) { // todo(vicb) - //assert(this._additionsHead === null); + // assert(this._additionsHead === null); this._additionsTail = this._additionsHead = record; } else { // todo(vicb) - //assert(_additionsTail._nextAdded === null); - //assert(record._nextAdded === null); + // assert(_additionsTail._nextAdded === null); + // assert(record._nextAdded === null); this._additionsTail = this._additionsTail._nextAdded = record; } return record; } - _insertAfter(record:CollectionChangeRecord, prevRecord:CollectionChangeRecord, - index:int):CollectionChangeRecord { + _insertAfter(record: CollectionChangeRecord, prevRecord: CollectionChangeRecord, + index: int): CollectionChangeRecord { // todo(vicb) - //assert(record != prevRecord); - //assert(record._next === null); - //assert(record._prev === null); + // assert(record != prevRecord); + // assert(record._next === null); + // assert(record._prev === null); - var next:CollectionChangeRecord = prevRecord === null ? this._itHead :prevRecord._next; + var next: CollectionChangeRecord = prevRecord === null ? this._itHead : prevRecord._next; // todo(vicb) - //assert(next != record); - //assert(prevRecord != record); + // assert(next != record); + // assert(prevRecord != record); record._next = next; record._prev = prevRecord; if (next === null) { @@ -401,11 +390,11 @@ export class IterableChanges extends Pipe { return record; } - _remove(record:CollectionChangeRecord):CollectionChangeRecord { + _remove(record: CollectionChangeRecord): CollectionChangeRecord { return this._addToRemovals(this._unlink(record)); } - _unlink(record:CollectionChangeRecord):CollectionChangeRecord { + _unlink(record: CollectionChangeRecord): CollectionChangeRecord { if (this._linkedRecords !== null) { this._linkedRecords.remove(record); } @@ -414,8 +403,8 @@ export class IterableChanges extends Pipe { var next = record._next; // todo(vicb) - //assert((record._prev = null) === null); - //assert((record._next = null) === null); + // assert((record._prev = null) === null); + // assert((record._next = null) === null); if (prev === null) { this._itHead = next; @@ -431,9 +420,9 @@ export class IterableChanges extends Pipe { return record; } - _addToMoves(record:CollectionChangeRecord, toIndex:int):CollectionChangeRecord { + _addToMoves(record: CollectionChangeRecord, toIndex: int): CollectionChangeRecord { // todo(vicb) - //assert(record._nextMoved === null); + // assert(record._nextMoved === null); if (record.previousIndex === toIndex) { return record; @@ -441,18 +430,18 @@ export class IterableChanges extends Pipe { if (this._movesTail === null) { // todo(vicb) - //assert(_movesHead === null); + // assert(_movesHead === null); this._movesTail = this._movesHead = record; } else { // todo(vicb) - //assert(_movesTail._nextMoved === null); + // assert(_movesTail._nextMoved === null); this._movesTail = this._movesTail._nextMoved = record; } return record; } - _addToRemovals(record:CollectionChangeRecord):CollectionChangeRecord { + _addToRemovals(record: CollectionChangeRecord): CollectionChangeRecord { if (this._unlinkedRecords === null) { this._unlinkedRecords = new _DuplicateMap(); } @@ -462,21 +451,21 @@ export class IterableChanges extends Pipe { if (this._removalsTail === null) { // todo(vicb) - //assert(_removalsHead === null); + // assert(_removalsHead === null); this._removalsTail = this._removalsHead = record; record._prevRemoved = null; } else { // todo(vicb) - //assert(_removalsTail._nextRemoved === null); - //assert(record._nextRemoved === null); + // assert(_removalsTail._nextRemoved === null); + // assert(record._nextRemoved === null); record._prevRemoved = this._removalsTail; this._removalsTail = this._removalsTail._nextRemoved = record; } return record; } - toString():string { - var record:CollectionChangeRecord; + toString(): string { + var record: CollectionChangeRecord; var list = []; for (record = this._itHead; record !== null; record = record._next) { @@ -502,10 +491,8 @@ export class IterableChanges extends Pipe { ListWrapper.push(removals, record); } - return "collection: " + list.join(', ') + "\n" + - "previous: " + previous.join(', ') + "\n" + - "additions: " + additions.join(', ') + "\n" + - "moves: " + moves.join(', ') + "\n" + + return "collection: " + list.join(', ') + "\n" + "previous: " + previous.join(', ') + "\n" + + "additions: " + additions.join(', ') + "\n" + "moves: " + moves.join(', ') + "\n" + "removals: " + removals.join(', ') + "\n"; } } @@ -513,17 +500,20 @@ export class IterableChanges extends Pipe { /** * @exportedAs angular2/pipes */ -export class CollectionChangeRecord { - currentIndex:int; - previousIndex:int; +export class CollectionChangeRecord { + currentIndex: int; + previousIndex: int; item; - _nextPrevious:CollectionChangeRecord; - _prev:CollectionChangeRecord; _next:CollectionChangeRecord; - _prevDup:CollectionChangeRecord; _nextDup:CollectionChangeRecord; - _prevRemoved:CollectionChangeRecord; _nextRemoved:CollectionChangeRecord; - _nextAdded:CollectionChangeRecord; - _nextMoved:CollectionChangeRecord; + _nextPrevious: CollectionChangeRecord; + _prev: CollectionChangeRecord; + _next: CollectionChangeRecord; + _prevDup: CollectionChangeRecord; + _nextDup: CollectionChangeRecord; + _prevRemoved: CollectionChangeRecord; + _nextRemoved: CollectionChangeRecord; + _nextAdded: CollectionChangeRecord; + _nextMoved: CollectionChangeRecord; constructor(item) { this.currentIndex = null; @@ -541,18 +531,18 @@ export class CollectionChangeRecord { this._nextMoved = null; } - toString():string { + toString(): string { return this.previousIndex === this.currentIndex ? - stringify(this.item) : - stringify(this.item) + '[' + stringify(this.previousIndex) + '->' + - stringify(this.currentIndex) + ']'; + stringify(this.item) : + stringify(this.item) + '[' + stringify(this.previousIndex) + '->' + + stringify(this.currentIndex) + ']'; } } // A linked list of CollectionChangeRecords with the same CollectionChangeRecord.item class _DuplicateItemRecordList { - _head:CollectionChangeRecord; - _tail:CollectionChangeRecord; + _head: CollectionChangeRecord; + _tail: CollectionChangeRecord; constructor() { this._head = null; @@ -564,14 +554,14 @@ class _DuplicateItemRecordList { * * Note: by design all records in the list of duplicates hold the same value in record.item. */ - add(record:CollectionChangeRecord) { + add(record: CollectionChangeRecord) { if (this._head === null) { this._head = this._tail = record; record._nextDup = null; record._prevDup = null; } else { // todo(vicb) - //assert(record.item == _head.item || + // assert(record.item == _head.item || // record.item is num && record.item.isNaN && _head.item is num && _head.item.isNaN); this._tail._nextDup = record; record._prevDup = this._tail; @@ -582,14 +572,14 @@ class _DuplicateItemRecordList { // Returns a CollectionChangeRecord having CollectionChangeRecord.item == item and // CollectionChangeRecord.currentIndex >= afterIndex - get(item, afterIndex:int):CollectionChangeRecord { - var record:CollectionChangeRecord; + get(item, afterIndex: int): CollectionChangeRecord { + var record: CollectionChangeRecord; for (record = this._head; record !== null; record = record._nextDup) { if ((afterIndex === null || afterIndex < record.currentIndex) && - looseIdentical(record.item, item)) { - return record; - } + looseIdentical(record.item, item)) { + return record; } + } return null; } @@ -598,9 +588,9 @@ class _DuplicateItemRecordList { * * Returns whether the list of duplicates is empty. */ - remove(record:CollectionChangeRecord):boolean { + remove(record: CollectionChangeRecord): boolean { // todo(vicb) - //assert(() { + // assert(() { // // verify that the record being removed is in the list. // for (CollectionChangeRecord cursor = _head; cursor != null; cursor = cursor._nextDup) { // if (identical(cursor, record)) return true; @@ -608,8 +598,8 @@ class _DuplicateItemRecordList { // return false; //}); - var prev:CollectionChangeRecord = record._prevDup; - var next:CollectionChangeRecord = record._nextDup; + var prev: CollectionChangeRecord = record._prevDup; + var next: CollectionChangeRecord = record._nextDup; if (prev === null) { this._head = next; } else { @@ -625,12 +615,10 @@ class _DuplicateItemRecordList { } class _DuplicateMap { - map:Map; - constructor() { - this.map = MapWrapper.create(); - } + map: Map; + constructor() { this.map = MapWrapper.create(); } - put(record:CollectionChangeRecord) { + put(record: CollectionChangeRecord) { // todo(vicb) handle corner cases var key = getMapKey(record.item); @@ -649,7 +637,7 @@ class _DuplicateMap { * Use case: `[a, b, c, a, a]` if we are at index `3` which is the second `a` then asking if we * have any more `a`s needs to return the last `a` not the first or second. */ - get(value, afterIndex = null):CollectionChangeRecord { + get(value, afterIndex = null): CollectionChangeRecord { var key = getMapKey(value); var recordList = MapWrapper.get(this.map, key); @@ -661,11 +649,11 @@ class _DuplicateMap { * * The list of duplicates also is removed from the map if it gets empty. */ - remove(record:CollectionChangeRecord):CollectionChangeRecord { + remove(record: CollectionChangeRecord): CollectionChangeRecord { var key = getMapKey(record.item); // todo(vicb) - //assert(this.map.containsKey(key)); - var recordList:_DuplicateItemRecordList = MapWrapper.get(this.map, key); + // assert(this.map.containsKey(key)); + var recordList: _DuplicateItemRecordList = MapWrapper.get(this.map, key); // Remove the list of duplicates when it gets empty if (recordList.remove(record)) { MapWrapper.delete(this.map, key); @@ -673,15 +661,9 @@ class _DuplicateMap { return record; } - get isEmpty():boolean { - return MapWrapper.size(this.map) === 0; - } + get isEmpty(): boolean { return MapWrapper.size(this.map) === 0; } - clear() { - MapWrapper.clear(this.map); - } + clear() { MapWrapper.clear(this.map); } - toString():string { - return '_DuplicateMap(' + stringify(this.map) + ')'; - } + toString(): string { return '_DuplicateMap(' + stringify(this.map) + ')'; } } diff --git a/modules/angular2/src/change_detection/pipes/keyvalue_changes.js b/modules/angular2/src/change_detection/pipes/keyvalue_changes.ts similarity index 67% rename from modules/angular2/src/change_detection/pipes/keyvalue_changes.js rename to modules/angular2/src/change_detection/pipes/keyvalue_changes.ts index e5542782d2..abb0afeb6c 100644 --- a/modules/angular2/src/change_detection/pipes/keyvalue_changes.js +++ b/modules/angular2/src/change_detection/pipes/keyvalue_changes.ts @@ -3,38 +3,36 @@ import {stringify, looseIdentical, isJsObject, CONST} from 'angular2/src/facade/ import {WrappedValue, Pipe, PipeFactory} from './pipe'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + /** * @exportedAs angular2/pipes */ +@CONST() export class KeyValueChangesFactory extends PipeFactory { - @CONST() - constructor() { - super(); - } + constructor() { super(); } - supports(obj):boolean { - return KeyValueChanges.supportsObj(obj); - } + supports(obj): boolean { return KeyValueChanges.supportsObj(obj); } - create(cdRef):Pipe { - return new KeyValueChanges(); - } + create(cdRef): Pipe { return new KeyValueChanges(); } } /** * @exportedAs angular2/pipes */ export class KeyValueChanges extends Pipe { - _records:Map; - - _mapHead:KVChangeRecord; - _previousMapHead:KVChangeRecord; - _changesHead:KVChangeRecord; - _changesTail:KVChangeRecord; - _additionsHead:KVChangeRecord; - _additionsTail:KVChangeRecord; - _removalsHead:KVChangeRecord; - _removalsTail:KVChangeRecord; + private _records: Map; + private _mapHead: KVChangeRecord; + private _previousMapHead: KVChangeRecord; + private _changesHead: KVChangeRecord; + private _changesTail: KVChangeRecord; + private _additionsHead: KVChangeRecord; + private _additionsTail: KVChangeRecord; + private _removalsHead: KVChangeRecord; + private _removalsTail: KVChangeRecord; constructor() { super(); @@ -49,15 +47,11 @@ export class KeyValueChanges extends Pipe { this._removalsTail = null; } - static supportsObj(obj):boolean { - return obj instanceof Map || isJsObject(obj); - } + static supportsObj(obj): boolean { return obj instanceof Map || isJsObject(obj); } - supports(obj):boolean { - return KeyValueChanges.supportsObj(obj); - } + supports(obj): boolean { return KeyValueChanges.supportsObj(obj); } - transform(map){ + transform(map): any { if (this.check(map)) { return WrappedValue.wrap(this); } else { @@ -65,54 +59,53 @@ export class KeyValueChanges extends Pipe { } } - get isDirty():boolean { - return this._additionsHead !== null || - this._changesHead !== null || + get isDirty(): boolean { + return this._additionsHead !== null || this._changesHead !== null || this._removalsHead !== null; } - forEachItem(fn:Function) { - var record:KVChangeRecord; + forEachItem(fn: Function) { + var record: KVChangeRecord; for (record = this._mapHead; record !== null; record = record._next) { fn(record); } } - forEachPreviousItem(fn:Function) { - var record:KVChangeRecord; + forEachPreviousItem(fn: Function) { + var record: KVChangeRecord; for (record = this._previousMapHead; record !== null; record = record._nextPrevious) { fn(record); } } - forEachChangedItem(fn:Function) { - var record:KVChangeRecord; + forEachChangedItem(fn: Function) { + var record: KVChangeRecord; for (record = this._changesHead; record !== null; record = record._nextChanged) { fn(record); } } - forEachAddedItem(fn:Function){ - var record:KVChangeRecord; + forEachAddedItem(fn: Function) { + var record: KVChangeRecord; for (record = this._additionsHead; record !== null; record = record._nextAdded) { fn(record); } } - forEachRemovedItem(fn:Function){ - var record:KVChangeRecord; + forEachRemovedItem(fn: Function) { + var record: KVChangeRecord; for (record = this._removalsHead; record !== null; record = record._nextRemoved) { fn(record); } } - check(map):boolean { + check(map): boolean { this._reset(); var records = this._records; - var oldSeqRecord:KVChangeRecord = this._mapHead; - var lastOldSeqRecord:KVChangeRecord = null; - var lastNewSeqRecord:KVChangeRecord = null; - var seqChanged:boolean = false; + var oldSeqRecord: KVChangeRecord = this._mapHead; + var lastOldSeqRecord: KVChangeRecord = null; + var lastNewSeqRecord: KVChangeRecord = null; + var seqChanged: boolean = false; this._forEach(map, (value, key) => { var newSeqRecord; @@ -160,11 +153,9 @@ export class KeyValueChanges extends Pipe { _reset() { if (this.isDirty) { - var record:KVChangeRecord; + var record: KVChangeRecord; // Record the state of the mapping - for (record = this._previousMapHead = this._mapHead; - record !== null; - record = record._next) { + for (record = this._previousMapHead = this._mapHead; record !== null; record = record._next) { record._nextPrevious = record._next; } @@ -177,7 +168,7 @@ export class KeyValueChanges extends Pipe { } // todo(vicb) once assert is supported - //assert(() { + // assert(() { // var r = _changesHead; // while (r != null) { // var nextRecord = r._nextChanged; @@ -207,7 +198,7 @@ export class KeyValueChanges extends Pipe { } } - _truncate(lastRecord:KVChangeRecord, record:KVChangeRecord) { + _truncate(lastRecord: KVChangeRecord, record: KVChangeRecord) { while (record !== null) { if (lastRecord === null) { this._mapHead = null; @@ -216,7 +207,7 @@ export class KeyValueChanges extends Pipe { } var nextRecord = record._next; // todo(vicb) assert - //assert((() { + // assert((() { // record._next = null; // return true; //})); @@ -225,26 +216,25 @@ export class KeyValueChanges extends Pipe { record = nextRecord; } - for (var rec:KVChangeRecord = this._removalsHead; rec !== null; rec = rec._nextRemoved) { + for (var rec: KVChangeRecord = this._removalsHead; rec !== null; rec = rec._nextRemoved) { rec.previousValue = rec.currentValue; rec.currentValue = null; MapWrapper.delete(this._records, rec.key); } } - _isInRemovals(record:KVChangeRecord) { - return record === this._removalsHead || - record._nextRemoved !== null || + _isInRemovals(record: KVChangeRecord) { + return record === this._removalsHead || record._nextRemoved !== null || record._prevRemoved !== null; } - _addToRemovals(record:KVChangeRecord) { + _addToRemovals(record: KVChangeRecord) { // todo(vicb) assert - //assert(record._next == null); - //assert(record._nextAdded == null); - //assert(record._nextChanged == null); - //assert(record._nextRemoved == null); - //assert(record._prevRemoved == null); + // assert(record._next == null); + // assert(record._nextAdded == null); + // assert(record._nextChanged == null); + // assert(record._nextRemoved == null); + // assert(record._prevRemoved == null); if (this._removalsHead === null) { this._removalsHead = this._removalsTail = record; } else { @@ -254,7 +244,7 @@ export class KeyValueChanges extends Pipe { } } - _removeFromSeq(prev:KVChangeRecord, record:KVChangeRecord) { + _removeFromSeq(prev: KVChangeRecord, record: KVChangeRecord) { var next = record._next; if (prev === null) { this._mapHead = next; @@ -262,17 +252,17 @@ export class KeyValueChanges extends Pipe { prev._next = next; } // todo(vicb) assert - //assert((() { + // assert((() { // record._next = null; // return true; //})()); } - _removeFromRemovals(record:KVChangeRecord) { + _removeFromRemovals(record: KVChangeRecord) { // todo(vicb) assert - //assert(record._next == null); - //assert(record._nextAdded == null); - //assert(record._nextChanged == null); + // assert(record._next == null); + // assert(record._nextAdded == null); + // assert(record._nextChanged == null); var prev = record._prevRemoved; var next = record._nextRemoved; @@ -289,13 +279,13 @@ export class KeyValueChanges extends Pipe { record._prevRemoved = record._nextRemoved = null; } - _addToAdditions(record:KVChangeRecord) { + _addToAdditions(record: KVChangeRecord) { // todo(vicb): assert - //assert(record._next == null); - //assert(record._nextAdded == null); - //assert(record._nextChanged == null); - //assert(record._nextRemoved == null); - //assert(record._prevRemoved == null); + // assert(record._next == null); + // assert(record._nextAdded == null); + // assert(record._nextChanged == null); + // assert(record._nextRemoved == null); + // assert(record._prevRemoved == null); if (this._additionsHead === null) { this._additionsHead = this._additionsTail = record; } else { @@ -304,12 +294,12 @@ export class KeyValueChanges extends Pipe { } } - _addToChanges(record:KVChangeRecord) { + _addToChanges(record: KVChangeRecord) { // todo(vicb) assert - //assert(record._nextAdded == null); - //assert(record._nextChanged == null); - //assert(record._nextRemoved == null); - //assert(record._prevRemoved == null); + // assert(record._nextAdded == null); + // assert(record._nextChanged == null); + // assert(record._nextRemoved == null); + // assert(record._prevRemoved == null); if (this._changesHead === null) { this._changesHead = this._changesTail = record; } else { @@ -318,13 +308,13 @@ export class KeyValueChanges extends Pipe { } } - toString():string { + toString(): string { var items = []; var previous = []; var changes = []; var additions = []; var removals = []; - var record:KVChangeRecord; + var record: KVChangeRecord; for (record = this._mapHead; record !== null; record = record._next) { ListWrapper.push(items, stringify(record)); @@ -342,14 +332,12 @@ export class KeyValueChanges extends Pipe { ListWrapper.push(removals, stringify(record)); } - return "map: " + items.join(', ') + "\n" + - "previous: " + previous.join(', ') + "\n" + - "additions: " + additions.join(', ') + "\n" + - "changes: " + changes.join(', ') + "\n" + + return "map: " + items.join(', ') + "\n" + "previous: " + previous.join(', ') + "\n" + + "additions: " + additions.join(', ') + "\n" + "changes: " + changes.join(', ') + "\n" + "removals: " + removals.join(', ') + "\n"; } - _forEach(obj, fn:Function) { + _forEach(obj, fn: Function) { if (obj instanceof Map) { MapWrapper.forEach(obj, fn); } else { @@ -368,12 +356,12 @@ export class KVChangeRecord { previousValue; currentValue; - _nextPrevious:KVChangeRecord; - _next:KVChangeRecord; - _nextAdded:KVChangeRecord; - _nextRemoved:KVChangeRecord; - _prevRemoved:KVChangeRecord; - _nextChanged:KVChangeRecord; + _nextPrevious: KVChangeRecord; + _next: KVChangeRecord; + _nextAdded: KVChangeRecord; + _nextRemoved: KVChangeRecord; + _prevRemoved: KVChangeRecord; + _nextChanged: KVChangeRecord; constructor(key) { this.key = key; @@ -388,10 +376,10 @@ export class KVChangeRecord { this._nextChanged = null; } - toString():string { + toString(): string { return looseIdentical(this.previousValue, this.currentValue) ? - stringify(this.key) : - (stringify(this.key) + '[' + stringify(this.previousValue) + '->' + - stringify(this.currentValue) + ']'); + stringify(this.key) : + (stringify(this.key) + '[' + stringify(this.previousValue) + '->' + + stringify(this.currentValue) + ']'); } } diff --git a/modules/angular2/src/change_detection/pipes/null_pipe.js b/modules/angular2/src/change_detection/pipes/null_pipe.js deleted file mode 100644 index b20cab8b2f..0000000000 --- a/modules/angular2/src/change_detection/pipes/null_pipe.js +++ /dev/null @@ -1,48 +0,0 @@ -import {isBlank, CONST} from 'angular2/src/facade/lang'; -import {Pipe, WrappedValue, PipeFactory} from './pipe'; - -/** - * @exportedAs angular2/pipes - */ -export class NullPipeFactory extends PipeFactory { - @CONST() - constructor() { - super(); - } - - supports(obj):boolean { - return NullPipe.supportsObj(obj); - } - - create(cdRef):Pipe { - return new NullPipe(); - } -} - -/** - * @exportedAs angular2/pipes - */ -export class NullPipe extends Pipe { - called:boolean; - constructor() { - super(); - this.called = false; - } - - static supportsObj(obj):boolean { - return isBlank(obj); - } - - supports(obj) { - return NullPipe.supportsObj(obj); - } - - transform(value) { - if (! this.called) { - this.called = true; - return WrappedValue.wrap(null); - } else { - return null; - } - } -} diff --git a/modules/angular2/src/change_detection/pipes/null_pipe.ts b/modules/angular2/src/change_detection/pipes/null_pipe.ts new file mode 100644 index 0000000000..b87da8b40e --- /dev/null +++ b/modules/angular2/src/change_detection/pipes/null_pipe.ts @@ -0,0 +1,43 @@ +import {isBlank, CONST} from 'angular2/src/facade/lang'; +import {Pipe, WrappedValue, PipeFactory} from './pipe'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +/** + * @exportedAs angular2/pipes + */ +@CONST() +export class NullPipeFactory extends PipeFactory { + constructor() { super(); } + + supports(obj): boolean { return NullPipe.supportsObj(obj); } + + create(cdRef): Pipe { return new NullPipe(); } +} + +/** + * @exportedAs angular2/pipes + */ +export class NullPipe extends Pipe { + called: boolean; + constructor() { + super(); + this.called = false; + } + + static supportsObj(obj): boolean { return isBlank(obj); } + + supports(obj) { return NullPipe.supportsObj(obj); } + + transform(value) { + if (!this.called) { + this.called = true; + return WrappedValue.wrap(null); + } else { + return null; + } + } +} diff --git a/modules/angular2/src/change_detection/pipes/pipe.js b/modules/angular2/src/change_detection/pipes/pipe.ts similarity index 62% rename from modules/angular2/src/change_detection/pipes/pipe.js rename to modules/angular2/src/change_detection/pipes/pipe.ts index 18c959406f..243e6b5bc4 100644 --- a/modules/angular2/src/change_detection/pipes/pipe.js +++ b/modules/angular2/src/change_detection/pipes/pipe.ts @@ -1,20 +1,22 @@ import {ABSTRACT, BaseException, CONST} from 'angular2/src/facade/lang'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + /** - * Indicates that the result of a {@link Pipe} transformation has changed even though the reference has not changed. + * Indicates that the result of a {@link Pipe} transformation has changed even though the reference + *has not changed. * * The wrapped value will be unwrapped by change detection, and the unwrapped value will be stored. * * @exportedAs angular2/pipes */ export class WrappedValue { - wrapped:any; + constructor(public wrapped: any) {} - constructor(wrapped:any) { - this.wrapped = wrapped; - } - - static wrap(value:any):WrappedValue { + static wrap(value: any): WrappedValue { var w = _wrappedValues[_wrappedIndex++ % 5]; w.wrapped = value; return w; @@ -53,26 +55,25 @@ var _wrappedIndex = 0; * @exportedAs angular2/pipes */ export class Pipe { - supports(obj):boolean {return false;} + supports(obj): boolean { return false; } onDestroy() {} - transform(value:any):any {return null;} + transform(value: any): any { return null; } } -@ABSTRACT() +// TODO: vsavkin: make it an interface +@CONST() export class PipeFactory { - @CONST() - constructor() { + supports(obs): boolean { + _abstract(); + return false; } - supports(obs):boolean { - return _abstract(); - } - - create(cdRef):Pipe { - return _abstract(); + create(cdRef): Pipe { + _abstract(); + return null; } } function _abstract() { - return new BaseException('This method is abstract'); + throw new BaseException('This method is abstract'); } diff --git a/modules/angular2/src/change_detection/pipes/pipe_registry.js b/modules/angular2/src/change_detection/pipes/pipe_registry.ts similarity index 59% rename from modules/angular2/src/change_detection/pipes/pipe_registry.js rename to modules/angular2/src/change_detection/pipes/pipe_registry.ts index f0f5a6df0d..9811e95b3c 100644 --- a/modules/angular2/src/change_detection/pipes/pipe_registry.js +++ b/modules/angular2/src/change_detection/pipes/pipe_registry.ts @@ -1,25 +1,25 @@ import {List, ListWrapper} from 'angular2/src/facade/collection'; import {isBlank, isPresent, BaseException, CONST} from 'angular2/src/facade/lang'; import {Pipe} from './pipe'; -import {Injectable} from 'angular2/src/di/annotations_impl'; +import {Injectable} from 'angular2/src/di/decorators'; import {ChangeDetectorRef} from '../change_detector_ref'; +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + @Injectable() export class PipeRegistry { - config; + constructor(public config) {} - constructor(config){ - this.config = config; - } - - get(type:string, obj, cdRef:ChangeDetectorRef):Pipe { + get(type: string, obj, cdRef: ChangeDetectorRef): Pipe { var listOfConfigs = this.config[type]; if (isBlank(listOfConfigs)) { throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`); } - var matchingConfig = ListWrapper.find(listOfConfigs, - (pipeConfig) => pipeConfig.supports(obj)); + var matchingConfig = ListWrapper.find(listOfConfigs, (pipeConfig) => pipeConfig.supports(obj)); if (isBlank(matchingConfig)) { throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`); diff --git a/modules/angular2/src/change_detection/proto_change_detector.js b/modules/angular2/src/change_detection/proto_change_detector.js deleted file mode 100644 index f0dc58110c..0000000000 --- a/modules/angular2/src/change_detection/proto_change_detector.js +++ /dev/null @@ -1,368 +0,0 @@ -import {isPresent, isBlank, BaseException, Type, isString} from 'angular2/src/facade/lang'; -import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; - -import { - AccessMember, - Assignment, - AST, - ASTWithSource, - AstVisitor, - Binary, - Chain, - Conditional, - Pipe, - FunctionCall, - ImplicitReceiver, - Interpolation, - KeyedAccess, - LiteralArray, - LiteralMap, - LiteralPrimitive, - MethodCall, - PrefixNot - } from './parser/ast'; - -import {ChangeDispatcher, ChangeDetector, ProtoChangeDetector} from './interfaces'; -import {ChangeDetectionUtil} from './change_detection_util'; -import {DynamicChangeDetector} from './dynamic_change_detector'; -import {ChangeDetectorJITGenerator} from './change_detection_jit_generator'; -import {PipeRegistry} from './pipes/pipe_registry'; -import {BindingRecord} from './binding_record'; -import {DirectiveRecord, DirectiveIndex} from './directive_record'; - -import {coalesce} from './coalesce'; - -import { - ProtoRecord, - RECORD_TYPE_SELF, - RECORD_TYPE_PROPERTY, - RECORD_TYPE_LOCAL, - RECORD_TYPE_INVOKE_METHOD, - RECORD_TYPE_CONST, - RECORD_TYPE_INVOKE_CLOSURE, - RECORD_TYPE_PRIMITIVE_OP, - RECORD_TYPE_KEYED_ACCESS, - RECORD_TYPE_PIPE, - RECORD_TYPE_BINDING_PIPE, - RECORD_TYPE_INTERPOLATE - } from './proto_record'; - -export class DynamicProtoChangeDetector extends ProtoChangeDetector { - _pipeRegistry:PipeRegistry; - _records:List; - _bindingRecords:List; - _variableBindings:List; - _directiveRecords:List; - _changeControlStrategy:string; - - constructor(pipeRegistry:PipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) { - super(); - this._pipeRegistry = pipeRegistry; - this._bindingRecords = bindingRecords; - this._variableBindings = variableBindings; - this._directiveRecords = directiveRecords; - this._changeControlStrategy = changeControlStrategy; - } - - instantiate(dispatcher:any) { - this._createRecordsIfNecessary(); - return new DynamicChangeDetector(this._changeControlStrategy, dispatcher, - this._pipeRegistry, this._records, this._directiveRecords); - } - - _createRecordsIfNecessary() { - if (isBlank(this._records)) { - var recordBuilder = new ProtoRecordBuilder(); - ListWrapper.forEach(this._bindingRecords, (b) => { - recordBuilder.addAst(b, this._variableBindings); - }); - this._records = coalesce(recordBuilder.records); - } - } -} - -var _jitProtoChangeDetectorClassCounter:number = 0; -export class JitProtoChangeDetector extends ProtoChangeDetector { - _factory:Function; - _pipeRegistry; - _bindingRecords:List; - _variableBindings:List; - _directiveRecords:List; - _changeControlStrategy:string; - - constructor(pipeRegistry, bindingRecords:List, variableBindings:List, directiveRecords:List, changeControlStrategy:string) { - super(); - this._pipeRegistry = pipeRegistry; - this._factory = null; - this._bindingRecords = bindingRecords; - this._variableBindings = variableBindings; - this._directiveRecords = directiveRecords; - this._changeControlStrategy = changeControlStrategy; - } - - instantiate(dispatcher:any) { - this._createFactoryIfNecessary(); - return this._factory(dispatcher, this._pipeRegistry); - } - - _createFactoryIfNecessary() { - if (isBlank(this._factory)) { - var recordBuilder = new ProtoRecordBuilder(); - ListWrapper.forEach(this._bindingRecords, (b) => { - recordBuilder.addAst(b, this._variableBindings); - }); - var c = _jitProtoChangeDetectorClassCounter++; - var records = coalesce(recordBuilder.records); - var typeName = `ChangeDetector${c}`; - this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records, - this._directiveRecords).generate(); - } - } -} - -class ProtoRecordBuilder { - records:List; - - constructor() { - this.records = []; - } - - addAst(b:BindingRecord, variableBindings:List = null) { - var last = ListWrapper.last(this.records); - if (isPresent(last) && last.bindingRecord.directiveRecord == b.directiveRecord) { - last.lastInDirective = false; - } - - var pr = _ConvertAstIntoProtoRecords.convert(b, this.records.length, variableBindings); - if (! ListWrapper.isEmpty(pr)) { - var last = ListWrapper.last(pr); - last.lastInBinding = true; - last.lastInDirective = true; - - this.records = ListWrapper.concat(this.records, pr); - } - } -} - -class _ConvertAstIntoProtoRecords { - protoRecords:List; - bindingRecord:BindingRecord; - variableBindings:List; - contextIndex:number; - expressionAsString:string; - - constructor(bindingRecord:BindingRecord, contextIndex:number, expressionAsString:string, variableBindings:List) { - this.protoRecords = []; - this.bindingRecord = bindingRecord; - this.contextIndex = contextIndex; - this.expressionAsString = expressionAsString; - this.variableBindings = variableBindings; - } - - static convert(b:BindingRecord, contextIndex:number, variableBindings:List) { - var c = new _ConvertAstIntoProtoRecords(b, contextIndex, b.ast.toString(), variableBindings); - b.ast.visit(c); - return c.protoRecords; - } - - visitImplicitReceiver(ast:ImplicitReceiver) { - return this.bindingRecord.implicitReceiver; - } - - visitInterpolation(ast:Interpolation) { - var args = this._visitAll(ast.expressions); - return this._addRecord(RECORD_TYPE_INTERPOLATE, "interpolate", _interpolationFn(ast.strings), - args, ast.strings, 0); - } - - visitLiteralPrimitive(ast:LiteralPrimitive) { - return this._addRecord(RECORD_TYPE_CONST, "literal", ast.value, [], null, 0); - } - - visitAccessMember(ast:AccessMember) { - var receiver = ast.receiver.visit(this); - if (isPresent(this.variableBindings) && - ListWrapper.contains(this.variableBindings, ast.name) && - ast.receiver instanceof ImplicitReceiver) { - return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); - } else { - return this._addRecord(RECORD_TYPE_PROPERTY, ast.name, ast.getter, [], null, receiver); - } - } - - visitMethodCall(ast:MethodCall) {; - var receiver = ast.receiver.visit(this); - var args = this._visitAll(ast.args); - if (isPresent(this.variableBindings) && ListWrapper.contains(this.variableBindings, ast.name)) { - var target = this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); - return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target); - } else { - return this._addRecord(RECORD_TYPE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver); - } - } - - visitFunctionCall(ast:FunctionCall) { - var target = ast.target.visit(this); - var args = this._visitAll(ast.args); - return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target); - } - - visitLiteralArray(ast:LiteralArray) { - var primitiveName = `arrayFn${ast.expressions.length}`; - return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, primitiveName, _arrayFn(ast.expressions.length), - this._visitAll(ast.expressions), null, 0); - } - - visitLiteralMap(ast:LiteralMap) { - return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _mapPrimitiveName(ast.keys), - ChangeDetectionUtil.mapFn(ast.keys), this._visitAll(ast.values), null, 0); - } - - visitBinary(ast:Binary) { - var left = ast.left.visit(this); - var right = ast.right.visit(this); - return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _operationToPrimitiveName(ast.operation), - _operationToFunction(ast.operation), [left, right], null, 0); - } - - visitPrefixNot(ast:PrefixNot) { - var exp = ast.expression.visit(this) - return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "operation_negate", - ChangeDetectionUtil.operation_negate, [exp], null, 0); - } - - visitConditional(ast:Conditional) { - var c = ast.condition.visit(this); - var t = ast.trueExp.visit(this); - var f = ast.falseExp.visit(this); - return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "cond", - ChangeDetectionUtil.cond, [c,t,f], null, 0); - } - - visitPipe(ast:Pipe) { - var value = ast.exp.visit(this); - var type = ast.inBinding ? RECORD_TYPE_BINDING_PIPE : RECORD_TYPE_PIPE; - return this._addRecord(type, ast.name, ast.name, [], null, value); - } - - visitKeyedAccess(ast:KeyedAccess) { - var obj = ast.obj.visit(this); - var key = ast.key.visit(this); - return this._addRecord(RECORD_TYPE_KEYED_ACCESS, "keyedAccess", - ChangeDetectionUtil.keyedAccess, [key], null, obj); - } - - _visitAll(asts:List) { - var res = ListWrapper.createFixedSize(asts.length); - for (var i = 0; i < asts.length; ++i) { - res[i] = asts[i].visit(this); - } - return res; - } - - _addRecord(type, name, funcOrValue, args, fixedArgs, context) { - var selfIndex = ++ this.contextIndex; - if (context instanceof DirectiveIndex) { - ListWrapper.push(this.protoRecords, - new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context, selfIndex, - this.bindingRecord, this.expressionAsString, false, false)); - } else { - ListWrapper.push(this.protoRecords, - new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null, selfIndex, - this.bindingRecord, this.expressionAsString, false, false)); - } - return selfIndex; - } -} - - -function _arrayFn(length:number):Function { - switch (length) { - case 0: return ChangeDetectionUtil.arrayFn0; - case 1: return ChangeDetectionUtil.arrayFn1; - case 2: return ChangeDetectionUtil.arrayFn2; - case 3: return ChangeDetectionUtil.arrayFn3; - case 4: return ChangeDetectionUtil.arrayFn4; - case 5: return ChangeDetectionUtil.arrayFn5; - case 6: return ChangeDetectionUtil.arrayFn6; - case 7: return ChangeDetectionUtil.arrayFn7; - case 8: return ChangeDetectionUtil.arrayFn8; - case 9: return ChangeDetectionUtil.arrayFn9; - default: throw new BaseException(`Does not support literal maps with more than 9 elements`); - } -} - -function _mapPrimitiveName(keys:List) { - var stringifiedKeys = ListWrapper.join( - ListWrapper.map(keys, (k) => isString(k) ? `"${k}"` : `${k}`), - ", "); - return `mapFn([${stringifiedKeys}])`; -} - -function _operationToPrimitiveName(operation:string):string { - switch(operation) { - case '+' : return "operation_add"; - case '-' : return "operation_subtract"; - case '*' : return "operation_multiply"; - case '/' : return "operation_divide"; - case '%' : return "operation_remainder"; - case '==' : return "operation_equals"; - case '!=' : return "operation_not_equals"; - case '<' : return "operation_less_then"; - case '>' : return "operation_greater_then"; - case '<=' : return "operation_less_or_equals_then"; - case '>=' : return "operation_greater_or_equals_then"; - case '&&' : return "operation_logical_and"; - case '||' : return "operation_logical_or"; - default: throw new BaseException(`Unsupported operation ${operation}`); - } -} - -function _operationToFunction(operation:string):Function { - switch(operation) { - case '+' : return ChangeDetectionUtil.operation_add; - case '-' : return ChangeDetectionUtil.operation_subtract; - case '*' : return ChangeDetectionUtil.operation_multiply; - case '/' : return ChangeDetectionUtil.operation_divide; - case '%' : return ChangeDetectionUtil.operation_remainder; - case '==' : return ChangeDetectionUtil.operation_equals; - case '!=' : return ChangeDetectionUtil.operation_not_equals; - case '<' : return ChangeDetectionUtil.operation_less_then; - case '>' : return ChangeDetectionUtil.operation_greater_then; - case '<=' : return ChangeDetectionUtil.operation_less_or_equals_then; - case '>=' : return ChangeDetectionUtil.operation_greater_or_equals_then; - case '&&' : return ChangeDetectionUtil.operation_logical_and; - case '||' : return ChangeDetectionUtil.operation_logical_or; - default: throw new BaseException(`Unsupported operation ${operation}`); - } -} - -function s(v) { - return isPresent(v) ? `${v}` : ''; -} - -function _interpolationFn(strings:List) { - var length = strings.length; - var c0 = length > 0 ? strings[0] : null; - var c1 = length > 1 ? strings[1] : null; - var c2 = length > 2 ? strings[2] : null; - var c3 = length > 3 ? strings[3] : null; - var c4 = length > 4 ? strings[4] : null; - var c5 = length > 5 ? strings[5] : null; - var c6 = length > 6 ? strings[6] : null; - var c7 = length > 7 ? strings[7] : null; - var c8 = length > 8 ? strings[8] : null; - var c9 = length > 9 ? strings[9] : null; - switch (length - 1) { - case 1: return (a1) => c0 + s(a1) + c1; - case 2: return (a1, a2) => c0 + s(a1) + c1 + s(a2) + c2; - case 3: return (a1, a2, a3) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3; - case 4: return (a1, a2, a3, a4) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4; - case 5: return (a1, a2, a3, a4, a5) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5; - case 6: return (a1, a2, a3, a4, a5, a6) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6; - case 7: return (a1, a2, a3, a4, a5, a6, a7) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7; - case 8: return (a1, a2, a3, a4, a5, a6, a7, a8) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7 + s(a8) + c8; - case 9: return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7 + s(a8) + c8 + s(a9) + c9; - default: throw new BaseException(`Does not support more than 9 expressions`); - } -} diff --git a/modules/angular2/src/change_detection/proto_change_detector.ts b/modules/angular2/src/change_detection/proto_change_detector.ts new file mode 100644 index 0000000000..6b93fc2c29 --- /dev/null +++ b/modules/angular2/src/change_detection/proto_change_detector.ts @@ -0,0 +1,406 @@ +import {isPresent, isBlank, BaseException, Type, isString} from 'angular2/src/facade/lang'; +import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; + +import { + AccessMember, + Assignment, + AST, + ASTWithSource, + AstVisitor, + Binary, + Chain, + Conditional, + Pipe, + FunctionCall, + ImplicitReceiver, + Interpolation, + KeyedAccess, + LiteralArray, + LiteralMap, + LiteralPrimitive, + MethodCall, + PrefixNot +} from './parser/ast'; + +import {ChangeDispatcher, ChangeDetector, ProtoChangeDetector} from './interfaces'; +import {ChangeDetectionUtil} from './change_detection_util'; +import {DynamicChangeDetector} from './dynamic_change_detector'; +import {ChangeDetectorJITGenerator} from './change_detection_jit_generator'; +import {PipeRegistry} from './pipes/pipe_registry'; +import {BindingRecord} from './binding_record'; +import {DirectiveRecord, DirectiveIndex} from './directive_record'; + +import {coalesce} from './coalesce'; + +import { + ProtoRecord, + RECORD_TYPE_SELF, + RECORD_TYPE_PROPERTY, + RECORD_TYPE_LOCAL, + RECORD_TYPE_INVOKE_METHOD, + RECORD_TYPE_CONST, + RECORD_TYPE_INVOKE_CLOSURE, + RECORD_TYPE_PRIMITIVE_OP, + RECORD_TYPE_KEYED_ACCESS, + RECORD_TYPE_PIPE, + RECORD_TYPE_BINDING_PIPE, + RECORD_TYPE_INTERPOLATE +} from './proto_record'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + + +export class DynamicProtoChangeDetector extends ProtoChangeDetector { + _records: List; + + constructor(private _pipeRegistry: PipeRegistry, private _bindingRecords: List, + private _variableBindings: List, private _directiveRecords: List, + private _changeControlStrategy: string) { + super(); + } + + instantiate(dispatcher: any) { + this._createRecordsIfNecessary(); + return new DynamicChangeDetector(this._changeControlStrategy, dispatcher, this._pipeRegistry, + this._records, this._directiveRecords); + } + + _createRecordsIfNecessary() { + if (isBlank(this._records)) { + var recordBuilder = new ProtoRecordBuilder(); + ListWrapper.forEach(this._bindingRecords, + (b) => { recordBuilder.addAst(b, this._variableBindings); }); + this._records = coalesce(recordBuilder.records); + } + } +} + +var _jitProtoChangeDetectorClassCounter: number = 0; +export class JitProtoChangeDetector extends ProtoChangeDetector { + _factory: Function; + + constructor(private _pipeRegistry, private _bindingRecords: List, + private _variableBindings: List, private _directiveRecords: List, + private _changeControlStrategy: string) { + super(); + this._factory = null; + } + + instantiate(dispatcher: any) { + this._createFactoryIfNecessary(); + return this._factory(dispatcher, this._pipeRegistry); + } + + _createFactoryIfNecessary() { + if (isBlank(this._factory)) { + var recordBuilder = new ProtoRecordBuilder(); + ListWrapper.forEach(this._bindingRecords, + (b) => { recordBuilder.addAst(b, this._variableBindings); }); + var c = _jitProtoChangeDetectorClassCounter++; + var records = coalesce(recordBuilder.records); + var typeName = `ChangeDetector${c}`; + this._factory = new ChangeDetectorJITGenerator(typeName, this._changeControlStrategy, records, + this._directiveRecords) + .generate(); + } + } +} + +class ProtoRecordBuilder { + records: List; + + constructor() { this.records = []; } + + addAst(b: BindingRecord, variableBindings: List < any >= null) { + var last = ListWrapper.last(this.records); + if (isPresent(last) && last.bindingRecord.directiveRecord == b.directiveRecord) { + last.lastInDirective = false; + } + + var pr = _ConvertAstIntoProtoRecords.convert(b, this.records.length, variableBindings); + if (!ListWrapper.isEmpty(pr)) { + var last = ListWrapper.last(pr); + last.lastInBinding = true; + last.lastInDirective = true; + + this.records = ListWrapper.concat(this.records, pr); + } + } +} + +class _ConvertAstIntoProtoRecords { + protoRecords: List; + + constructor(private bindingRecord: BindingRecord, private contextIndex: number, + private expressionAsString: string, private variableBindings: List) { + this.protoRecords = []; + } + + static convert(b: BindingRecord, contextIndex: number, variableBindings: List) { + var c = new _ConvertAstIntoProtoRecords(b, contextIndex, b.ast.toString(), variableBindings); + b.ast.visit(c); + return c.protoRecords; + } + + visitImplicitReceiver(ast: ImplicitReceiver) { return this.bindingRecord.implicitReceiver; } + + visitInterpolation(ast: Interpolation) { + var args = this._visitAll(ast.expressions); + return this._addRecord(RECORD_TYPE_INTERPOLATE, "interpolate", _interpolationFn(ast.strings), + args, ast.strings, 0); + } + + visitLiteralPrimitive(ast: LiteralPrimitive) { + return this._addRecord(RECORD_TYPE_CONST, "literal", ast.value, [], null, 0); + } + + visitAccessMember(ast: AccessMember) { + var receiver = ast.receiver.visit(this); + if (isPresent(this.variableBindings) && ListWrapper.contains(this.variableBindings, ast.name) && + ast.receiver instanceof + ImplicitReceiver) { + return this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); + } else { + return this._addRecord(RECORD_TYPE_PROPERTY, ast.name, ast.getter, [], null, receiver); + } + } + + visitMethodCall(ast: MethodCall) { + ; + var receiver = ast.receiver.visit(this); + var args = this._visitAll(ast.args); + if (isPresent(this.variableBindings) && ListWrapper.contains(this.variableBindings, ast.name)) { + var target = this._addRecord(RECORD_TYPE_LOCAL, ast.name, ast.name, [], null, receiver); + return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target); + } else { + return this._addRecord(RECORD_TYPE_INVOKE_METHOD, ast.name, ast.fn, args, null, receiver); + } + } + + visitFunctionCall(ast: FunctionCall) { + var target = ast.target.visit(this); + var args = this._visitAll(ast.args); + return this._addRecord(RECORD_TYPE_INVOKE_CLOSURE, "closure", null, args, null, target); + } + + visitLiteralArray(ast: LiteralArray) { + var primitiveName = `arrayFn${ast.expressions.length}`; + return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, primitiveName, + _arrayFn(ast.expressions.length), this._visitAll(ast.expressions), null, + 0); + } + + visitLiteralMap(ast: LiteralMap) { + return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _mapPrimitiveName(ast.keys), + ChangeDetectionUtil.mapFn(ast.keys), this._visitAll(ast.values), null, + 0); + } + + visitBinary(ast: Binary) { + var left = ast.left.visit(this); + var right = ast.right.visit(this); + return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, _operationToPrimitiveName(ast.operation), + _operationToFunction(ast.operation), [left, right], null, 0); + } + + visitPrefixNot(ast: PrefixNot) { + var exp = ast.expression.visit(this); + return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "operation_negate", + ChangeDetectionUtil.operation_negate, [exp], null, 0); + } + + visitConditional(ast: Conditional) { + var c = ast.condition.visit(this); + var t = ast.trueExp.visit(this); + var f = ast.falseExp.visit(this); + return this._addRecord(RECORD_TYPE_PRIMITIVE_OP, "cond", ChangeDetectionUtil.cond, [c, t, f], + null, 0); + } + + visitPipe(ast: Pipe) { + var value = ast.exp.visit(this); + var type = ast.inBinding ? RECORD_TYPE_BINDING_PIPE : RECORD_TYPE_PIPE; + return this._addRecord(type, ast.name, ast.name, [], null, value); + } + + visitKeyedAccess(ast: KeyedAccess) { + var obj = ast.obj.visit(this); + var key = ast.key.visit(this); + return this._addRecord(RECORD_TYPE_KEYED_ACCESS, "keyedAccess", ChangeDetectionUtil.keyedAccess, + [key], null, obj); + } + + _visitAll(asts: List) { + var res = ListWrapper.createFixedSize(asts.length); + for (var i = 0; i < asts.length; ++i) { + res[i] = asts[i].visit(this); + } + return res; + } + + _addRecord(type, name, funcOrValue, args, fixedArgs, context) { + var selfIndex = ++this.contextIndex; + if (context instanceof DirectiveIndex) { + ListWrapper.push( + this.protoRecords, + new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context, selfIndex, + this.bindingRecord, this.expressionAsString, false, false)); + } else { + ListWrapper.push( + this.protoRecords, + new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null, selfIndex, + this.bindingRecord, this.expressionAsString, false, false)); + } + return selfIndex; + } +} + + +function _arrayFn(length: number): Function { + switch (length) { + case 0: + return ChangeDetectionUtil.arrayFn0; + case 1: + return ChangeDetectionUtil.arrayFn1; + case 2: + return ChangeDetectionUtil.arrayFn2; + case 3: + return ChangeDetectionUtil.arrayFn3; + case 4: + return ChangeDetectionUtil.arrayFn4; + case 5: + return ChangeDetectionUtil.arrayFn5; + case 6: + return ChangeDetectionUtil.arrayFn6; + case 7: + return ChangeDetectionUtil.arrayFn7; + case 8: + return ChangeDetectionUtil.arrayFn8; + case 9: + return ChangeDetectionUtil.arrayFn9; + default: + throw new BaseException(`Does not support literal maps with more than 9 elements`); + } +} + +function _mapPrimitiveName(keys: List) { + var stringifiedKeys = + ListWrapper.join(ListWrapper.map(keys, (k) => isString(k) ? `"${k}"` : `${k}`), ", "); + return `mapFn([${stringifiedKeys}])`; +} + +function _operationToPrimitiveName(operation: string): string { + switch (operation) { + case '+': + return "operation_add"; + case '-': + return "operation_subtract"; + case '*': + return "operation_multiply"; + case '/': + return "operation_divide"; + case '%': + return "operation_remainder"; + case '==': + return "operation_equals"; + case '!=': + return "operation_not_equals"; + case '<': + return "operation_less_then"; + case '>': + return "operation_greater_then"; + case '<=': + return "operation_less_or_equals_then"; + case '>=': + return "operation_greater_or_equals_then"; + case '&&': + return "operation_logical_and"; + case '||': + return "operation_logical_or"; + default: + throw new BaseException(`Unsupported operation ${operation}`); + } +} + +function _operationToFunction(operation: string): Function { + switch (operation) { + case '+': + return ChangeDetectionUtil.operation_add; + case '-': + return ChangeDetectionUtil.operation_subtract; + case '*': + return ChangeDetectionUtil.operation_multiply; + case '/': + return ChangeDetectionUtil.operation_divide; + case '%': + return ChangeDetectionUtil.operation_remainder; + case '==': + return ChangeDetectionUtil.operation_equals; + case '!=': + return ChangeDetectionUtil.operation_not_equals; + case '<': + return ChangeDetectionUtil.operation_less_then; + case '>': + return ChangeDetectionUtil.operation_greater_then; + case '<=': + return ChangeDetectionUtil.operation_less_or_equals_then; + case '>=': + return ChangeDetectionUtil.operation_greater_or_equals_then; + case '&&': + return ChangeDetectionUtil.operation_logical_and; + case '||': + return ChangeDetectionUtil.operation_logical_or; + default: + throw new BaseException(`Unsupported operation ${operation}`); + } +} + +function s(v) { + return isPresent(v) ? `${v}` : ''; +} + +function _interpolationFn(strings: List) { + var length = strings.length; + var c0 = length > 0 ? strings[0] : null; + var c1 = length > 1 ? strings[1] : null; + var c2 = length > 2 ? strings[2] : null; + var c3 = length > 3 ? strings[3] : null; + var c4 = length > 4 ? strings[4] : null; + var c5 = length > 5 ? strings[5] : null; + var c6 = length > 6 ? strings[6] : null; + var c7 = length > 7 ? strings[7] : null; + var c8 = length > 8 ? strings[8] : null; + var c9 = length > 9 ? strings[9] : null; + switch (length - 1) { + case 1: + return (a1) => c0 + s(a1) + c1; + case 2: + return (a1, a2) => c0 + s(a1) + c1 + s(a2) + c2; + case 3: + return (a1, a2, a3) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3; + case 4: + return (a1, a2, a3, a4) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4; + case 5: + return (a1, a2, a3, a4, a5) => + c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5; + case 6: + return (a1, a2, a3, a4, a5, a6) => + c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + c4 + s(a5) + c5 + s(a6) + c6; + case 7: + return (a1, a2, a3, a4, a5, a6, a7) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7; + case 8: + return (a1, a2, a3, a4, a5, a6, a7, a8) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + s(a4) + + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + c7 + s(a8) + + c8; + case 9: + return (a1, a2, a3, a4, a5, a6, a7, a8, a9) => c0 + s(a1) + c1 + s(a2) + c2 + s(a3) + c3 + + s(a4) + c4 + s(a5) + c5 + s(a6) + c6 + s(a7) + + c7 + s(a8) + c8 + s(a9) + c9; + default: + throw new BaseException(`Does not support more than 9 expressions`); + } +} diff --git a/modules/angular2/src/change_detection/proto_record.js b/modules/angular2/src/change_detection/proto_record.js deleted file mode 100644 index 1731ce6f24..0000000000 --- a/modules/angular2/src/change_detection/proto_record.js +++ /dev/null @@ -1,66 +0,0 @@ -import {List} from 'angular2/src/facade/collection'; -import {BindingRecord} from './binding_record'; -import {DirectiveIndex} from './directive_record'; - -export const RECORD_TYPE_SELF = 0; -export const RECORD_TYPE_CONST = 1; -export const RECORD_TYPE_PRIMITIVE_OP = 2; -export const RECORD_TYPE_PROPERTY = 3; -export const RECORD_TYPE_LOCAL = 4; -export const RECORD_TYPE_INVOKE_METHOD = 5; -export const RECORD_TYPE_INVOKE_CLOSURE = 6; -export const RECORD_TYPE_KEYED_ACCESS = 7; -export const RECORD_TYPE_PIPE = 8; -export const RECORD_TYPE_BINDING_PIPE = 9; -export const RECORD_TYPE_INTERPOLATE = 10; - -export class ProtoRecord { - mode:number; - name:string; - funcOrValue:any; - args:List; - fixedArgs:List; - - contextIndex:number; - directiveIndex:DirectiveIndex; - - selfIndex:number; - bindingRecord:BindingRecord; - lastInBinding:boolean; - lastInDirective:boolean; - expressionAsString:string; - - constructor(mode:number, - name:string, - funcOrValue, - args:List, - fixedArgs:List, - contextIndex:number, - directiveIndex:DirectiveIndex, - selfIndex:number, - bindingRecord:BindingRecord, - expressionAsString:string, - lastInBinding:boolean, - lastInDirective:boolean) { - - this.mode = mode; - this.name = name; - this.funcOrValue = funcOrValue; - this.args = args; - this.fixedArgs = fixedArgs; - - this.contextIndex = contextIndex; - this.directiveIndex = directiveIndex; - - this.selfIndex = selfIndex; - this.bindingRecord = bindingRecord; - this.lastInBinding = lastInBinding; - this.lastInDirective = lastInDirective; - this.expressionAsString = expressionAsString; - } - - isPureFunction():boolean { - return this.mode === RECORD_TYPE_INTERPOLATE || - this.mode === RECORD_TYPE_PRIMITIVE_OP; - } -} diff --git a/modules/angular2/src/change_detection/proto_record.ts b/modules/angular2/src/change_detection/proto_record.ts new file mode 100644 index 0000000000..2bcf3033bf --- /dev/null +++ b/modules/angular2/src/change_detection/proto_record.ts @@ -0,0 +1,32 @@ +import {List} from 'angular2/src/facade/collection'; +import {BindingRecord} from './binding_record'; +import {DirectiveIndex} from './directive_record'; + +// HACK: workaround for Traceur behavior. +// It expects all transpiled modules to contain this marker. +// TODO: remove this when we no longer use traceur +export var __esModule = true; + +export const RECORD_TYPE_SELF = 0; +export const RECORD_TYPE_CONST = 1; +export const RECORD_TYPE_PRIMITIVE_OP = 2; +export const RECORD_TYPE_PROPERTY = 3; +export const RECORD_TYPE_LOCAL = 4; +export const RECORD_TYPE_INVOKE_METHOD = 5; +export const RECORD_TYPE_INVOKE_CLOSURE = 6; +export const RECORD_TYPE_KEYED_ACCESS = 7; +export const RECORD_TYPE_PIPE = 8; +export const RECORD_TYPE_BINDING_PIPE = 9; +export const RECORD_TYPE_INTERPOLATE = 10; + +export class ProtoRecord { + constructor(public mode: number, public name: string, public funcOrValue, public args: List, + public fixedArgs: List, public contextIndex: number, + public directiveIndex: DirectiveIndex, public selfIndex: number, + public bindingRecord: BindingRecord, public expressionAsString: string, + public lastInBinding: boolean, public lastInDirective: boolean) {} + + isPureFunction(): boolean { + return this.mode === RECORD_TYPE_INTERPOLATE || this.mode === RECORD_TYPE_PRIMITIVE_OP; + } +} diff --git a/modules/angular2/src/di/binding.ts b/modules/angular2/src/di/binding.ts index 98cff4724f..86284c6b85 100644 --- a/modules/angular2/src/di/binding.ts +++ b/modules/angular2/src/di/binding.ts @@ -449,7 +449,9 @@ function _constructDependencies(factoryFunction: Function, dependencies: List { var params = reflector.parameters(typeOrFunc); if (isBlank(params)) return []; - if (ListWrapper.any(params, (p) => isBlank(p))) throw new NoAnnotationError(typeOrFunc); + if (ListWrapper.any(params, (p) => isBlank(p))) { + throw new NoAnnotationError(typeOrFunc); + } return ListWrapper.map(params, (p) => _extractToken(typeOrFunc, p)); } diff --git a/modules/angular2/src/di/decorators.dart b/modules/angular2/src/di/decorators.dart index d3de503bf6..d4f3a4b5d1 100644 --- a/modules/angular2/src/di/decorators.dart +++ b/modules/angular2/src/di/decorators.dart @@ -1,3 +1,5 @@ library angular2.di.decorators; /* This file is empty because, Dart does not have decorators. */ + +export 'annotations.dart'; \ No newline at end of file diff --git a/modules/angular2/src/di/injector.ts b/modules/angular2/src/di/injector.ts index b2ebc38597..a26022544a 100644 --- a/modules/angular2/src/di/injector.ts +++ b/modules/angular2/src/di/injector.ts @@ -66,12 +66,12 @@ function _isWaiting(obj): boolean { * @exportedAs angular2/di */ export class Injector { - _bindings: List; - _instances: List; - _parent: Injector; - _defaultBindings: boolean; - _asyncStrategy: _AsyncInjectorStrategy; - _syncStrategy: _SyncInjectorStrategy; + private _bindings: List; + private _instances: List; + private _parent: Injector; + private _defaultBindings: boolean; + private _asyncStrategy: _AsyncInjectorStrategy; + private _syncStrategy: _SyncInjectorStrategy; /** * Turns a list of binding definitions into an internal resolved list of resolved bindings. diff --git a/modules/angular2/src/facade/async.ts b/modules/angular2/src/facade/async.ts index 614d866ab3..f7d60a8a95 100644 --- a/modules/angular2/src/facade/async.ts +++ b/modules/angular2/src/facade/async.ts @@ -52,7 +52,7 @@ export class PromiseWrapper { export class ObservableWrapper { - static subscribe(emitter: EventEmitter, onNext, onThrow = null, onReturn = null) { + static subscribe(emitter: Observable, onNext, onThrow = null, onReturn = null): Object { return emitter.observer({next: onNext, throw: onThrow, return: onReturn}); } @@ -69,7 +69,7 @@ export class ObservableWrapper { // TODO: vsavkin change to interface export class Observable { - observer(generator: any) {} + observer(generator: any): Object { return null; } } /** diff --git a/modules/angular2/src/facade/collection.ts b/modules/angular2/src/facade/collection.ts index 0e3b7dea23..5609b4ad12 100644 --- a/modules/angular2/src/facade/collection.ts +++ b/modules/angular2/src/facade/collection.ts @@ -117,9 +117,9 @@ export class ListWrapper { static indexOf(array: List, value, startIndex = -1) { return array.indexOf(value, startIndex); } - static reduce(list: List, - fn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, - init: T) { + static reduce(list: List, + fn: (accumValue: E, currentValue: T, currentIndex: number, array: T[]) => E, + init: E) { return list.reduce(fn, init); } static filter(array, pred: Function) { return array.filter(pred); } diff --git a/modules/angular2/src/reflection/reflection_capabilities.dart b/modules/angular2/src/reflection/reflection_capabilities.dart index 48e4d7004d..89542d5e32 100644 --- a/modules/angular2/src/reflection/reflection_capabilities.dart +++ b/modules/angular2/src/reflection/reflection_capabilities.dart @@ -5,6 +5,9 @@ import 'types.dart'; import 'dart:mirrors'; class ReflectionCapabilities { + ReflectionCapabilities([metadataReader]) { + } + Function factory(Type type) { ClassMirror classMirror = reflectType(type); MethodMirror ctor = classMirror.declarations[classMirror.simpleName]; diff --git a/modules/angular2/src/reflection/reflection_capabilities.ts b/modules/angular2/src/reflection/reflection_capabilities.ts index 54af88fd25..ad86d1b249 100644 --- a/modules/angular2/src/reflection/reflection_capabilities.ts +++ b/modules/angular2/src/reflection/reflection_capabilities.ts @@ -8,37 +8,39 @@ import {GetterFn, SetterFn, MethodFn} from './types'; export var __esModule = true; export class ReflectionCapabilities { - factory(type: Type): Function { - switch (type.length) { + private _reflect: any; + + constructor(reflect?: any) { this._reflect = isPresent(reflect) ? reflect : global.Reflect; } + + factory(t: Type): Function { + switch (t.length) { case 0: - return function() { return new type(); }; + return function() { return new t(); }; case 1: - return function(a1) { return new type(a1); }; + return function(a1) { return new t(a1); }; case 2: - return function(a1, a2) { return new type(a1, a2); }; + return function(a1, a2) { return new t(a1, a2); }; case 3: - return function(a1, a2, a3) { return new type(a1, a2, a3); }; + return function(a1, a2, a3) { return new t(a1, a2, a3); }; case 4: - return function(a1, a2, a3, a4) { return new type(a1, a2, a3, a4); }; + return function(a1, a2, a3, a4) { return new t(a1, a2, a3, a4); }; case 5: - return function(a1, a2, a3, a4, a5) { return new type(a1, a2, a3, a4, a5); }; + return function(a1, a2, a3, a4, a5) { return new t(a1, a2, a3, a4, a5); }; case 6: - return function(a1, a2, a3, a4, a5, a6) { return new type(a1, a2, a3, a4, a5, a6); }; + return function(a1, a2, a3, a4, a5, a6) { return new t(a1, a2, a3, a4, a5, a6); }; case 7: - return function(a1, a2, a3, a4, a5, a6, a7) { - return new type(a1, a2, a3, a4, a5, a6, a7); - }; + return function(a1, a2, a3, a4, a5, a6, a7) { return new t(a1, a2, a3, a4, a5, a6, a7); }; case 8: return function(a1, a2, a3, a4, a5, a6, a7, a8) { - return new type(a1, a2, a3, a4, a5, a6, a7, a8); + return new t(a1, a2, a3, a4, a5, a6, a7, a8); }; case 9: return function(a1, a2, a3, a4, a5, a6, a7, a8, a9) { - return new type(a1, a2, a3, a4, a5, a6, a7, a8, a9); + return new t(a1, a2, a3, a4, a5, a6, a7, a8, a9); }; case 10: return function(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) { - return new type(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + return new t(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); }; }; @@ -68,9 +70,9 @@ export class ReflectionCapabilities { if (isPresent(typeOfFunc.parameters)) { return typeOfFunc.parameters; } - if (isPresent(global.Reflect) && isPresent(global.Reflect.getMetadata)) { - var paramAnnotations = global.Reflect.getMetadata('parameters', typeOfFunc); - var paramTypes = global.Reflect.getMetadata('design:paramtypes', typeOfFunc); + if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) { + var paramAnnotations = this._reflect.getMetadata('parameters', typeOfFunc); + var paramTypes = this._reflect.getMetadata('design:paramtypes', typeOfFunc); if (isPresent(paramTypes) || isPresent(paramAnnotations)) { return this._zipTypesAndAnnotaions(paramTypes, paramAnnotations); } @@ -83,8 +85,8 @@ export class ReflectionCapabilities { if (isPresent(typeOfFunc.annotations)) { return typeOfFunc.annotations; } - if (isPresent(global.Reflect) && isPresent(global.Reflect.getMetadata)) { - var annotations = global.Reflect.getMetadata('annotations', typeOfFunc); + if (isPresent(this._reflect) && isPresent(this._reflect.getMetadata)) { + var annotations = this._reflect.getMetadata('annotations', typeOfFunc); if (isPresent(annotations)) return annotations; } return []; diff --git a/modules/angular2/test/core/compiler/reflection_capabilities_spec.js b/modules/angular2/test/core/compiler/reflection_capabilities_spec.js index 210b4e13a4..e3dd1b9ea2 100644 --- a/modules/angular2/test/core/compiler/reflection_capabilities_spec.js +++ b/modules/angular2/test/core/compiler/reflection_capabilities_spec.js @@ -8,17 +8,6 @@ export function main() { rc = new ReflectionCapabilities(); }); - function mockReflect(mockData, cls) { - // This only makes sense for JS, but Dart passes trivially too. - if (!IS_DARTIUM) { - global.Reflect = { - 'getMetadata': (key, targetCls) => { - return (targetCls == cls) ? mockData[key] : null; - } - } - } - } - function assertTestClassAnnotations(annotations) { expect(annotations[0]).toBeAnInstanceOf(ClassDec1); expect(annotations[1]).toBeAnInstanceOf(ClassDec2); @@ -54,23 +43,34 @@ export function main() { expect(rc.parameters(TestClassTypesOnly)).toEqual([[P1], [P2]]); }); - if (!IS_DARTIUM) { // Mocking in the tests below is needed because the test runs through Traceur. // After the switch to TS the setup will have to change, where the direct key // access will be mocked, and the tests below will be direct. it('can read out class annotations though Reflect APIs', () => { - mockReflect(mockDataForTestClassDec, TestClassDec); + var rc = new ReflectionCapabilities({ + 'getMetadata': (key, targetCls) => { + return (targetCls == TestClassDec) ? mockDataForTestClassDec[key] : null; + } + }); assertTestClassAnnotations(rc.annotations(TestClassDec)); }); it('can read out parameter annotations though Reflect APIs', () => { - mockReflect(mockDataForTestClassDec, TestClassDec); + var rc = new ReflectionCapabilities({ + 'getMetadata': (key, targetCls) => { + return (targetCls == TestClassDec) ? mockDataForTestClassDec[key] : null; + } + }); assertTestClassParameters(rc.parameters(TestClassDec)); }); it('can read out parameter annotations though Reflect APIs for types only class', () => { - mockReflect(mockDataForTestClassTypesOnly, TestClassTypesOnlyDec); + var rc = new ReflectionCapabilities({ + 'getMetadata': (key, targetCls) => { + return (targetCls == TestClassTypesOnlyDec) ? mockDataForTestClassTypesOnly[key] : null; + } + }); expect(rc.parameters(TestClassTypesOnlyDec)).toEqual([[P1], [P2]]); }); } diff --git a/tools/broccoli/trees/node_tree.ts b/tools/broccoli/trees/node_tree.ts index 3c368a62f9..28ca14c644 100644 --- a/tools/broccoli/trees/node_tree.ts +++ b/tools/broccoli/trees/node_tree.ts @@ -100,6 +100,7 @@ module.exports = function makeNodeTree(destinationPath) { var typescriptTree = compileWithTypescript(modulesTree, { allowNonTsExtensions: false, + emitDecoratorMetadata: true, declaration: true, mapRoot: '', /* force sourcemaps to use relative path */ module: 'commonjs', diff --git a/tools/traceur-jasmine/index.js b/tools/traceur-jasmine/index.js index 385ec853b9..208a28e74b 100644 --- a/tools/traceur-jasmine/index.js +++ b/tools/traceur-jasmine/index.js @@ -5,6 +5,7 @@ var minijasminenode2 = require('minijasminenode2'); var path = require('path'); // Require traceur to exposes $traceurRuntime on global context so that CJS files can run require('traceur/bin/traceur-runtime.js'); +require('reflect-metadata/Reflect'); glob(process.argv[2], function (error, specFiles) { minijasminenode2.executeSpecs({