UNPKG

marko

Version:

Optimized runtime for Marko templates.

140 lines (139 loc) • 7.41 kB
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;