Skip to content

Commit 6c60c3e

Browse files
committed
feat(render): add initial implementation of render layer
1 parent 814d389 commit 6c60c3e

File tree

64 files changed

+7248
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+7248
-1
lines changed

modules/angular2/change_detection.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
export {AST} from './src/change_detection/parser/ast';
1+
export {
2+
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
3+
} from './src/change_detection/parser/ast';
24
export {Lexer} from './src/change_detection/parser/lexer';
35
export {Parser} from './src/change_detection/parser/parser';
46
export {Locals}

modules/angular2/src/change_detection/parser/ast.js

+66
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,72 @@ export class AstVisitor {
446446
visitPrefixNot(ast:PrefixNot) {}
447447
}
448448

449+
export class AstTransformer {
450+
visitImplicitReceiver(ast:ImplicitReceiver) {
451+
return new ImplicitReceiver();
452+
}
453+
454+
visitInterpolation(ast:Interpolation) {
455+
return new Interpolation(ast.strings, this.visitAll(ast.expressions));
456+
}
457+
458+
visitLiteralPrimitive(ast:LiteralPrimitive) {
459+
return new LiteralPrimitive(ast.value);
460+
}
461+
462+
visitAccessMember(ast:AccessMember) {
463+
return new AccessMember(ast.receiver.visit(this), ast.name, ast.getter, ast.setter);
464+
}
465+
466+
visitMethodCall(ast:MethodCall) {
467+
return new MethodCall(ast.receiver.visit(this), ast.name, ast.fn, this.visitAll(ast.args));
468+
}
469+
470+
visitFunctionCall(ast:FunctionCall) {
471+
return new FunctionCall(ast.target.visit(this), this.visitAll(ast.args));
472+
}
473+
474+
visitLiteralArray(ast:LiteralArray) {
475+
return new LiteralArray(this.visitAll(ast.expressions));
476+
}
477+
478+
visitLiteralMap(ast:LiteralMap) {
479+
return new LiteralMap(ast.keys, this.visitAll(ast.values));
480+
}
481+
482+
visitBinary(ast:Binary) {
483+
return new Binary(ast.operation, ast.left.visit(this), ast.right.visit(this));
484+
}
485+
486+
visitPrefixNot(ast:PrefixNot) {
487+
return new PrefixNot(ast.expression.visit(this));
488+
}
489+
490+
visitConditional(ast:Conditional) {
491+
return new Conditional(
492+
ast.condition.visit(this),
493+
ast.trueExp.visit(this),
494+
ast.falseExp.visit(this)
495+
);
496+
}
497+
498+
visitPipe(ast:Pipe) {
499+
return new Pipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.inBinding);
500+
}
501+
502+
visitKeyedAccess(ast:KeyedAccess) {
503+
return new KeyedAccess(ast.obj.visit(this), ast.key.visit(this));
504+
}
505+
506+
visitAll(asts:List) {
507+
var res = ListWrapper.createFixedSize(asts.length);
508+
for (var i = 0; i < asts.length; ++i) {
509+
res[i] = asts[i].visit(this);
510+
}
511+
return res;
512+
}
513+
}
514+
449515
var _evalListCache = [[],[0],[0,0],[0,0,0],[0,0,0,0],[0,0,0,0,0],
450516
[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],
451517
[0,0,0,0,0,0,0,0,0]];

modules/angular2/src/render/api.js

+226
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import {isPresent} from 'angular2/src/facade/lang';
2+
import {Promise} from 'angular2/src/facade/async';
3+
import {List, Map} from 'angular2/src/facade/collection';
4+
import {ASTWithSource} from 'angular2/change_detection';
5+
6+
/**
7+
* General notes:
8+
* We are already parsing expressions on the render side:
9+
* - this makes the ElementBinders more compact
10+
* (e.g. no need to distinguish interpolations from regular expressions from literals)
11+
* - allows to retrieve which properties should be accessed from the event
12+
* by looking at the expression
13+
* - we need the parse at least for the `template` attribute to match
14+
* directives in it
15+
* - render compiler is not on the critical path as
16+
* its output will be stored in precompiled templates.
17+
*/
18+
export class ElementBinder {
19+
index:number;
20+
parentIndex:number;
21+
distanceToParent:number;
22+
parentWithDirectivesIndex:number;
23+
distanceToParentWithDirectives:number;
24+
directives:List<DirectiveBinder>;
25+
nestedProtoView:ProtoView;
26+
propertyBindings: Map<string, ASTWithSource>;
27+
variableBindings: Map<string, ASTWithSource>;
28+
// Note: this contains a preprocessed AST
29+
// that replaced the values that should be extracted from the element
30+
// with a local name
31+
eventBindings: Map<string, ASTWithSource>;
32+
textBindings: List<ASTWithSource>;
33+
34+
constructor({
35+
index, parentIndex, distanceToParent, parentWithDirectivesIndex,
36+
distanceToParentWithDirectives, directives, nestedProtoView,
37+
propertyBindings, variableBindings,
38+
eventBindings, textBindings
39+
}) {
40+
this.index = index;
41+
this.parentIndex = parentIndex;
42+
this.distanceToParent = distanceToParent;
43+
this.parentWithDirectivesIndex = parentWithDirectivesIndex;
44+
this.distanceToParentWithDirectives = distanceToParentWithDirectives;
45+
this.directives = directives;
46+
this.nestedProtoView = nestedProtoView;
47+
this.propertyBindings = propertyBindings;
48+
this.variableBindings = variableBindings;
49+
this.eventBindings = eventBindings;
50+
this.textBindings = textBindings;
51+
}
52+
}
53+
54+
export class DirectiveBinder {
55+
// Index into the array of directives in the Template instance
56+
directiveIndex:any;
57+
propertyBindings: Map<string, ASTWithSource>;
58+
// Note: this contains a preprocessed AST
59+
// that replaced the values that should be extracted from the element
60+
// with a local name
61+
eventBindings: Map<string, ASTWithSource>;
62+
constructor({
63+
directiveIndex, propertyBindings, eventBindings
64+
}) {
65+
this.directiveIndex = directiveIndex;
66+
this.propertyBindings = propertyBindings;
67+
this.eventBindings = eventBindings;
68+
}
69+
}
70+
71+
export class ProtoView {
72+
render: ProtoViewRef;
73+
elementBinders:List<ElementBinder>;
74+
variableBindings: Map<string, string>;
75+
76+
constructor({render, elementBinders, variableBindings}) {
77+
this.render = render;
78+
this.elementBinders = elementBinders;
79+
this.variableBindings = variableBindings;
80+
}
81+
}
82+
83+
export class DirectiveMetadata {
84+
static get DECORATOR_TYPE() { return 0; }
85+
static get COMPONENT_TYPE() { return 1; }
86+
static get VIEWPORT_TYPE() { return 2; }
87+
id:any;
88+
selector:string;
89+
compileChildren:boolean;
90+
events:Map<string, string>;
91+
bind:Map<string, string>;
92+
setters:List<string>;
93+
type:number;
94+
constructor({id, selector, compileChildren, events, bind, setters, type}) {
95+
this.id = id;
96+
this.selector = selector;
97+
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
98+
this.events = events;
99+
this.bind = bind;
100+
this.setters = setters;
101+
this.type = type;
102+
}
103+
}
104+
105+
// An opaque reference to a ProtoView
106+
export class ProtoViewRef {}
107+
108+
// An opaque reference to a View
109+
export class ViewRef {}
110+
111+
export class ViewContainerRef {
112+
view:ViewRef;
113+
elementIndex:number;
114+
constructor(view:ViewRef, elementIndex: number) {
115+
this.view = view;
116+
this.elementIndex = elementIndex;
117+
}
118+
}
119+
120+
export class Template {
121+
componentId: string;
122+
absUrl: string;
123+
inline: string;
124+
directives: List<DirectiveMetadata>;
125+
126+
constructor({componentId, absUrl, inline, directives}) {
127+
this.componentId = componentId;
128+
this.absUrl = absUrl;
129+
this.inline = inline;
130+
this.directives = directives;
131+
}
132+
}
133+
134+
export class Renderer {
135+
/**
136+
* Compiles a single ProtoView. Non recursive so that
137+
* we don't need to serialize all possible components over the wire,
138+
* but only the needed ones based on previous calls.
139+
*/
140+
compile(template:Template):Promise<ProtoView> { return null; }
141+
142+
/**
143+
* Creates a new ProtoView with preset nested components,
144+
* which will be instantiated when this protoView is instantiated.
145+
* @param {List<ProtoViewRef>} protoViewRefs
146+
* ProtoView for every element with a component in this protoView or in a view container's protoView
147+
* @return {List<ProtoViewRef>}
148+
* new ProtoViewRef for the given protoView and all of its view container's protoViews
149+
*/
150+
mergeChildComponentProtoViews(protoViewRef:ProtoViewRef, protoViewRefs:List<ProtoViewRef>):List<ProtoViewRef> { return null; }
151+
152+
/**
153+
* Creats a ProtoView that will create a root view for the given element,
154+
* i.e. it will not clone the element but only attach other proto views to it.
155+
*/
156+
createRootProtoView(selectorOrElement):ProtoViewRef { return null; }
157+
158+
/**
159+
* Creates a view and all of its nested child components.
160+
* @return {List<ViewRef>} depth first list of nested child components
161+
*/
162+
createView(protoView:ProtoViewRef):List<ViewRef> { return null; }
163+
164+
/**
165+
* Destroys a view and returns it back into the pool.
166+
*/
167+
destroyView(view:ViewRef):void {}
168+
169+
/**
170+
* Inserts a detached view into a viewContainer.
171+
*/
172+
insertViewIntoContainer(vcRef:ViewContainerRef, view:ViewRef, atIndex):void {}
173+
174+
/**
175+
* Detaches a view from a container so that it can be inserted later on
176+
* Note: We are not return the ViewRef as this can't be done in sync,
177+
* so we assume that the caller knows which view is in which spot...
178+
*/
179+
detachViewFromContainer(vcRef:ViewContainerRef, atIndex:number):void {}
180+
181+
/**
182+
* Sets a property on an element.
183+
* Note: This will fail if the property was not mentioned previously as a propertySetter
184+
* in the Template.
185+
*/
186+
setElementProperty(view:ViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {}
187+
188+
/**
189+
* Installs a nested component in another view.
190+
* Note: only allowed if there is a dynamic component directive
191+
*/
192+
setDynamicComponentView(view:ViewRef, elementIndex:number, nestedViewRef:ViewRef):void {}
193+
194+
/**
195+
* This will set the value for a text node.
196+
* Note: This needs to be separate from setElementProperty as we don't have ElementBinders
197+
* for text nodes in the ProtoView either.
198+
*/
199+
setText(view:ViewRef, textNodeIndex:number, text:string):void {}
200+
201+
/**
202+
* Sets the dispatcher for all events that have been defined in the template or in directives
203+
* in the given view.
204+
*/
205+
setEventDispatcher(viewRef:ViewRef, dispatcher:EventDispatcher):void {}
206+
207+
/**
208+
* To be called at the end of the VmTurn so the API can buffer calls
209+
*/
210+
flush():void {}
211+
}
212+
213+
214+
/**
215+
* A dispatcher for all events happening in a view.
216+
*/
217+
export class EventDispatcher {
218+
/**
219+
* Called when an event was triggered for a on-* attribute on an element.
220+
* @param {List<any>} locals Locals to be used to evaluate the
221+
* event expressions
222+
*/
223+
dispatchEvent(
224+
elementIndex:number, eventName:string, locals:List<any>
225+
):void {}
226+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import {isBlank} from 'angular2/src/facade/lang';
2+
import {List, ListWrapper} from 'angular2/src/facade/collection';
3+
import {CompileElement} from './compile_element';
4+
import {CompileStep} from './compile_step';
5+
6+
/**
7+
* Controls the processing order of elements.
8+
* Right now it only allows to add a parent element.
9+
*/
10+
export class CompileControl {
11+
_steps:List<CompileStep>;
12+
_currentStepIndex:number;
13+
_parent:CompileElement;
14+
_results;
15+
_additionalChildren;
16+
constructor(steps) {
17+
this._steps = steps;
18+
this._currentStepIndex = 0;
19+
this._parent = null;
20+
this._results = null;
21+
this._additionalChildren = null;
22+
}
23+
24+
// only public so that it can be used by compile_pipeline
25+
internalProcess(results, startStepIndex, parent:CompileElement, current:CompileElement) {
26+
this._results = results;
27+
var previousStepIndex = this._currentStepIndex;
28+
var previousParent = this._parent;
29+
30+
for (var i=startStepIndex; i<this._steps.length; i++) {
31+
var step = this._steps[i];
32+
this._parent = parent;
33+
this._currentStepIndex = i;
34+
step.process(parent, current, this);
35+
parent = this._parent;
36+
}
37+
ListWrapper.push(results, current);
38+
39+
this._currentStepIndex = previousStepIndex;
40+
this._parent = previousParent;
41+
42+
var localAdditionalChildren = this._additionalChildren;
43+
this._additionalChildren = null;
44+
return localAdditionalChildren;
45+
}
46+
47+
addParent(newElement:CompileElement) {
48+
this.internalProcess(this._results, this._currentStepIndex+1, this._parent, newElement);
49+
this._parent = newElement;
50+
}
51+
52+
addChild(element:CompileElement) {
53+
if (isBlank(this._additionalChildren)) {
54+
this._additionalChildren = ListWrapper.create();
55+
}
56+
ListWrapper.push(this._additionalChildren, element);
57+
}
58+
}

0 commit comments

Comments
 (0)