This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

First pass at tracked properties

  • Loading branch information...
tomdale committed Mar 22, 2017
1 parent 2178e62 commit daab5a7f22009aebcd2d380c5dc8c45fd0eadc7e
Showing with 347 additions and 20 deletions.
  1. +7 −7 package.json
  2. +8 −12 src/component-manager.ts
  3. +2 −1 src/index.ts
  4. +169 −0 src/references.ts
  5. +160 −0 src/tracked.ts
  6. +1 −0 tsconfig.json
View
@@ -18,19 +18,19 @@
},
"dependencies": {
"@glimmer/di": "^0.1.9",
"@glimmer/interfaces": "^0.23.0-alpha.0",
"@glimmer/object-reference": "^0.23.0-alpha.0",
"@glimmer/reference": "^0.23.0-alpha.0",
"@glimmer/runtime": "^0.23.0-alpha.0",
"@glimmer/util": "^0.23.0-alpha.0",
"@glimmer/wire-format": "^0.23.0-alpha.0",
"@glimmer/interfaces": "^0.23.0-alpha.2",
"@glimmer/object-reference": "^0.23.0-alpha.2",
"@glimmer/reference": "0.23.0-alpha.2",
"@glimmer/runtime": "0.23.0-alpha.2",
"@glimmer/util": "0.23.0-alpha.2",
"@glimmer/wire-format": "^0.23.0-alpha.2",
"handlebars": "~3",
"simple-html-tokenizer": "^0.3.0"
},
"devDependencies": {
"@glimmer/application": "^0.3.0",
"@glimmer/compiler": "^0.23.0-alpha.0",
"@glimmer/build": "0.6.0",
"@glimmer/compiler": "^0.23.0-alpha.2",
"@glimmer/resolver": "^0.3.0",
"broccoli": "^1.1.0",
"broccoli-cli": "^1.0.0",
View
@@ -13,15 +13,11 @@ import {
Arguments,
Template
} from '@glimmer/runtime';
import {
UpdatableReference
} from '@glimmer/object-reference';
import {
VersionedPathReference
} from '@glimmer/reference';
import { Opaque } from '@glimmer/util';
import { Tag } from '@glimmer/reference';
import Component from './component';
import ComponentDefinition from './component-definition';
import { RootReference } from './references';
import { tagForObject } from './tracked';
export interface ConstructorOptions {
env: Environment;
@@ -63,8 +59,8 @@ export default class ComponentManager implements GlimmerComponentManager<Compone
return compiledLayout;
}
getSelf(component: Component): VersionedPathReference<Opaque> {
return new UpdatableReference(component);
getSelf(component: Component) {
return new RootReference(component);
}
didCreateElement(component: Component, element: Simple.Element) {
@@ -82,7 +78,7 @@ export default class ComponentManager implements GlimmerComponentManager<Compone
// component.didRender();
}
getTag() {
getTag(component: Component): null {
return null;
}
@@ -93,7 +89,7 @@ export default class ComponentManager implements GlimmerComponentManager<Compone
didUpdate() {}
getDestructor() {
getDestructor(): null {
return null;
}
}
}
View
@@ -1,3 +1,4 @@
export { default as default, ComponentFactory } from './component';
export { default as ComponentDefinition } from './component-definition';
export { default as ComponentManager } from './component-manager';
export { default as ComponentManager } from './component-manager';
export { tracked, setPropertyDidChange } from './tracked';
View
@@ -0,0 +1,169 @@
import {
dict
} from '@glimmer/util';
import {
PathReference,
CONSTANT_TAG,
ConstReference,
DirtyableTag,
UpdatableTag,
combine,
isConst,
Tag,
TagWrapper
} from '@glimmer/reference';
import {
ConditionalReference as GlimmerConditionalReference,
PrimitiveReference
} from '@glimmer/runtime';
import { tagForProperty } from "./tracked";
/**
* The base PathReference.
*/
export abstract class ComponentPathReference<T> implements PathReference<T> {
abstract value(): T;
abstract get tag(): Tag;
get(key: string): PathReference<any> {
return PropertyReference.create(this, key);
}
}
export abstract class CachedReference<T> extends ComponentPathReference<T> {
private _lastRevision: number | null = null;
private _lastValue: any = null;
abstract compute(): T;
value() {
let { tag, _lastRevision, _lastValue } = this;
if (!_lastRevision || !tag.validate(_lastRevision)) {
_lastValue = this._lastValue = this.compute();
this._lastRevision = tag.value();
}
return _lastValue;
}
}
export class RootReference extends ConstReference<object> {
private children = dict<RootPropertyReference>();
get(propertyKey: string) {
let ref = this.children[propertyKey];
if (!ref) {
ref = this.children[propertyKey] = new RootPropertyReference(this.inner, propertyKey);
}
return ref;
}
}
export abstract class PropertyReference extends CachedReference<any> {
static create(parentReference: PathReference<any>, propertyKey: string) {
if (isConst(parentReference)) {
return new RootPropertyReference(parentReference.value(), propertyKey);
} else {
return new NestedPropertyReference(parentReference, propertyKey);
}
}
get(key: string): PathReference<any> {
return new NestedPropertyReference(this, key);
}
}
export class RootPropertyReference extends PropertyReference {
tag: Tag;
private _parentValue: object;
private _propertyKey: string;
constructor(parentValue: object, propertyKey: string) {
super();
this._parentValue = parentValue;
this._propertyKey = propertyKey;
this.tag = tagForProperty(parentValue, propertyKey);
}
compute(): any {
return (this._parentValue as any)[this._propertyKey];
}
}
export class NestedPropertyReference extends PropertyReference {
public tag: Tag;
private _parentReference: PathReference<any>;
private _parentObjectTag: TagWrapper<UpdatableTag>;
private _propertyKey: string;
constructor(parentReference: PathReference<any>, propertyKey: string) {
super();
let parentReferenceTag = parentReference.tag;
let parentObjectTag = UpdatableTag.create(CONSTANT_TAG);
this._parentReference = parentReference;
this._parentObjectTag = parentObjectTag;
this._propertyKey = propertyKey;
this.tag = combine([parentReferenceTag, parentObjectTag]);
}
compute() {
let { _parentReference, _parentObjectTag, _propertyKey } = this;
let parentValue = _parentReference.value();
_parentObjectTag.inner.update(tagForProperty(parentValue, _propertyKey));
if (typeof parentValue === 'string' && _propertyKey === 'length') {
return parentValue.length;
}
if (typeof parentValue === 'object' && parentValue) {
return parentValue[_propertyKey];
} else {
return undefined;
}
}
}
export class UpdatableReference<T> extends ComponentPathReference<T> {
public tag: TagWrapper<DirtyableTag>;
private _value: T;
constructor(value: T) {
super();
this.tag = DirtyableTag.create();
this._value = value;
}
value() {
return this._value;
}
update(value: T) {
let { _value } = this;
if (value !== _value) {
this.tag.inner.dirty();
this._value = value;
}
}
}
export class ConditionalReference extends GlimmerConditionalReference {
static create(reference: PathReference<any>) {
if (isConst(reference)) {
let value = reference.value();
return PrimitiveReference.create(value);
}
return new ConditionalReference(reference);
}
}
Oops, something went wrong.

0 comments on commit daab5a7

Please sign in to comment.