/** * This file describes the interface between compilation time * and runtime. * * # Locators * * Compile time and runtime must share the same Locator. A Locator is an * object that describes the location of a template, and is roughly a * module name. The compiler and runtime may use the Locator to locally * resolve names relative to the template the name was found in, but must * share resolution rules between compilation time and runtime. * * For example, given this template with Locator * `{ module: 'components/Articles/Container' }: * * ``` * * ``` * * The compiler may resolve `` to `components/Articles/TabBar`. The * important thing is that the compiler and runtime share resolution rules. * * # CompileTimeLookup * * When compiling an application, the `CompileTimeLookup` is responsible * for resolving helpers, modifiers, components, and partials into "handles" * (numbers) that can be embedded into the program and used at runtime. * * # RuntimeResolver * * The `RuntimeResolver` has two responsibilities. * * 1. To turn handles created by the `CompileTimeLookup` into live helpers, * modifiers, components, and partials. * 2. To resolve dynamic components and partials at runtime that come from * calls to `{{component dynamic}}` or `{{partial dynamic}}`. * * The `CompileTimeLookup` and `RuntimeResolver` must maintain symmetry * between: * * * `resolver.resolve(lookup.lookupComponentDefinition(name, referrer))`; and * * `resolver.lookupComponentDefinition(name, referrer))` * * And between: * * * `resolver.resolve(lookup.lookupPartial(name, referrer))`; and * * `resolver.lookupPartial(name, referrer))` * * # Coupling * * In practice, the `CompileTimeLookup` and `RuntimeResolver` are two parts * of one system. The goal of this system is to allow the `CompileTimeLookup` * to do as much resolution as possible ahead of time, while still allowing * the `RuntimeResolver` to do dynamic resolution when necessary. */ import { Option } from './core'; import { ProgramSymbolTable } from './tier1/symbol-table'; import { ComponentDefinitionState, ComponentInstanceState } from './components'; import { CompilableProgram, Template, HandleResult } from './template'; import { CompileTimeCompilationContext } from './program'; import { Owner, ModifierDefinitionState, HelperDefinitionState } from './runtime'; import { InternalComponentCapability, InternalComponentManager } from './managers'; export interface CompileTimeComponent { handle: number; capabilities: InternalComponentCapability; compilable: Option; } export interface ResolvedComponentDefinition< D = ComponentDefinitionState, I = ComponentInstanceState, M extends InternalComponentManager = InternalComponentManager > { state: D; manager: M; template: Template | null; } export const enum ResolverContext { Component, Modifier, Helper, HelperOrComponent, } export interface CompileTimeResolver { lookupHelper(name: string, owner: O): Option; lookupModifier(name: string, owner: O): Option; lookupComponent(name: string, owner: O): Option; lookupPartial(name: string, owner: O): Option; // TODO: These are used to lookup keywords that are implemented as helpers/modifiers. // We should try to figure out a cleaner way to do this. lookupBuiltInHelper(name: string): Option; lookupBuiltInModifier(name: string): Option; } export interface PartialDefinition { name: string; // for debugging getPartial( context: CompileTimeCompilationContext ): { symbolTable: ProgramSymbolTable; handle: HandleResult }; } export interface RuntimeResolver { lookupComponent(name: string, owner: O): Option; lookupPartial(name: string, owner: O): Option; }