import { RevisionTag, ConstReference, PathReference, Reference } from '@glimmer/reference'; import { Option, Opaque } from '@glimmer/util'; export type Primitive = undefined | null | boolean | number | string; export class PrimitiveReference extends ConstReference implements PathReference { static create(value: T): PrimitiveReference { if (value === undefined) { return UNDEFINED_REFERENCE as PrimitiveReference; } else if (value === null) { return NULL_REFERENCE as PrimitiveReference; } else if (value === true) { return TRUE_REFERENCE as PrimitiveReference; } else if (value === false) { return FALSE_REFERENCE as PrimitiveReference; } else if (typeof value === 'number') { return new ValueReference(value as number) as PrimitiveReference; } else { return new StringReference(value as string) as any as PrimitiveReference; } } protected constructor(value: T) { super(value); } get(_key: string): PrimitiveReference { return UNDEFINED_REFERENCE; } } class StringReference extends PrimitiveReference { private lengthReference: Option> = null; get(key: string): PrimitiveReference { if (key === 'length') { let { lengthReference } = this; if (lengthReference === null) { lengthReference = this.lengthReference = new ValueReference(this.inner.length); } return lengthReference; } else { return super.get(key); } } } type Value = undefined | null | number | boolean; class ValueReference extends PrimitiveReference { constructor(value: T) { super(value); } } export const UNDEFINED_REFERENCE: PrimitiveReference = new ValueReference(undefined); export const NULL_REFERENCE: PrimitiveReference = new ValueReference(null); const TRUE_REFERENCE: PrimitiveReference = new ValueReference(true); const FALSE_REFERENCE: PrimitiveReference = new ValueReference(false); export class ConditionalReference implements Reference { public tag: RevisionTag; constructor(private inner: Reference) { this.tag = inner.tag; } value(): boolean { return this.toBool(this.inner.value()); } protected toBool(value: Opaque): boolean { return !!value; } }