marko
Version:
Optimized runtime for Marko templates.
140 lines (139 loc) • 7.41 kB
TypeScript
import { types as t } from "@marko/compiler";
import { ReservedId } from "../../common/types";
import * as BindingType from "./constants/binding-type";
import { type Opt, type SortedMany, type SortedOpt, Sorted } from "./optional";
import { type AssignedBindingExtra, type Read, type ReferencedExtra } from "./references";
import { type Section } from "./sections";
import { type Sources } from "./sources";
type BindingType = BindingType.Value;
export { BindingType };
export interface Binding {
/** Its scope accessor id, allocated per section once references finalize. */
id: number;
/** Creation order, never renumbered: the order `bindingUtil` sorts by. */
uid: number;
name: string;
originalName: string | undefined;
type: BindingType;
loc: t.SourceLocation | null;
section: Section;
closureSections: SortedOpt<Section>;
/** The id its closure accessors take, past its section's and ancestors' ids. */
closureId: number | undefined;
/** The identifier of each emitted assignment to it (set in finalize). */
assignments: Opt<AssignedBindingExtra>;
sources: undefined | Sources;
/** The intersection whose work computes it, or the nearest one it derives
* from. Set on alias roots only. */
intersection: Intersection | undefined;
/** The expressions its value is computed from, `false` for none; unset when
* analysis cannot see them, which makes it its own source. */
derivedFrom: Opt<t.NodeExtra> | false;
/** Its reads by expression, complete once `finalizeReferences` runs: pruning
* hands an expression's reads to the nearest ancestor it also reads. */
reads: Map<ReferencedExtra, Opt<Read>>;
aliases: Set<Binding>;
/** The sections reading it through a hoist: its own or its ancestors, so
* the first is the outermost. */
hoists: SortedOpt<Section>;
getters: Map<Getter["hoisted"], boolean>;
property: string | undefined;
propertyAliases: Map<string, Binding>;
excludeProperties: SortedOpt<string>;
/** Its properties code assigns in place (`obj.x = 1`), all of them for a
* computed one. */
assignedProperties: SortedOpt<string> | true;
aliasOf: Binding | undefined;
/** The value these `<for>` params iterate, by `of` or `in`. */
iterates: {
expr: t.NodeExtra;
type: "of" | "in";
} | undefined;
/** For an array rest, the source index it starts at: `rest[0]` of
* `[a, ...rest]` is the source's `[1]`. */
restOffset: number | undefined;
/** For a tag variable a child's `<return>` writes, the node binding of the
* tag rendering that child. */
returnedBy: Binding | undefined;
/** Scope ids it holds right after its own, up to its highest `ReservedId`:
* a controllable `<let>`'s change handler, or a tag's scope offset. */
reserveSize: number;
scopeAccessor: string | undefined;
/** A name declared for this value, or all of it but its `excludeProperties`
* (a rest element), even once pruned. */
declaredAlias: Binding | undefined;
/** The attribute tag `<for>` param a local closure holds in its section. */
localOf: Binding | undefined;
/** An attribute tag `<for>` param's local closure in each content the loop
* creates that reads it. */
localClosures: Map<Section, Binding> | undefined;
/** Declared by its own name in its own section; an alias only in a pattern
* holding a rest or where what it reads from is hidden from a read of it. */
declared: boolean;
nullable: boolean;
/** Settled only once `finalizeReferences` runs at program analyze exit. */
pruned: boolean | undefined;
/** In a template's or `<define>`'s params tree, which known call sites set
* directly. */
exposed: boolean;
/** Read on invocation from its own scope slot, so its signal stores it. */
hasLazyReads: boolean;
}
/** A param of a template or of a tag body, which its caller supplies. */
export interface ParamBinding extends Binding {
type: typeof BindingType.param;
}
export type ReferencedBindings = SortedOpt<Binding>;
export type Intersection = SortedMany<Binding>;
/** Every member computed from one local source in the same pass, or the
* intersection's own render id and the tag whose scope offset it renders after. */
export type IntersectionMeta = {
source: Binding;
id?: undefined;
returnedBy?: undefined;
} | {
source: undefined;
id: number;
returnedBy: Binding | undefined;
};
export interface Getter {
hoisted: Section | false;
invoked: boolean;
}
export declare const getBindings: () => Set<Binding>;
export declare function createBinding(name: string, type: Binding["type"], refSection: Section, aliased?: Binding["aliasOf"], property?: string, excludeProperties?: SortedOpt<string>, loc?: t.SourceLocation | null, refDeclared?: boolean, restOffset?: number): Binding;
export declare function reserveId(binding: Binding, offset: ReservedId): void;
export declare function ensurePropertyAlias(binding: Binding, property: string): Binding;
export declare function addAssignedProperty(binding: Binding, property: string | undefined): void;
export declare function getAssignedObject(binding: Binding): Binding | undefined;
export declare function getPropertyAlias(binding: Binding, properties: Opt<string>): Binding | undefined;
export declare function getDeepestPropertyAlias(binding: Binding, properties: Opt<string>): Binding;
export declare function compareReferences(a: ReferencedBindings, b: ReferencedBindings): number;
/**
* reference group priority is sorted by number of references,
* then if needed by reference order.
*/
export declare function compareIntersections(a: Intersection, b: Intersection): number;
export declare function getAliasRoot(binding: Binding): Binding;
export declare const bindingUtil: Sorted<Binding>;
export declare const propsUtil: Sorted<string>;
export declare function getCanonicalBinding(binding: Binding): Binding;
export declare function someAlias<A>(binding: Binding, test: (binding: Binding, arg: A) => boolean, arg: A, directOnly?: boolean): boolean;
export declare function someUpToAliasRoot<A>(binding: Binding | undefined, test: (binding: Binding, arg: A) => boolean, arg: A): boolean;
export declare function getNearestDeclared(binding: Binding): Binding | undefined;
export declare function getDeclaredAlias(binding: Binding): false | Binding | undefined;
export declare function isDirectAlias(binding: Binding): boolean;
export declare function isRest(binding: Binding): boolean;
export declare function getDebugAccess(binding: Binding, toParam: boolean, formatProperty: (property: string) => string): {
root: Binding;
access: string;
};
export declare function isTemplateParam(binding: Binding): boolean;
export declare function getDebugName(binding: Binding): string;
export declare function getDebugNames(refs: ReferencedBindings): string;
export declare function getDebugNamesAsIdentifier(refs: ReferencedBindings): string;
export declare function isInvokeOnlyBinding(binding: Binding): boolean;
export declare function isOwnBinding(binding: Binding): boolean;
export declare function hasNonConstantPropertyAlias(ref: Binding): boolean;
export declare function getPropertyPath(binding: Binding, ancestor: Binding): Opt<string>;
export declare function isIndexProperty(property: string): boolean;