import type { Maybe } from '@dereekb/util'; import { type AstNode, type ImportRegistry } from './util'; /** * One segment of a folded upload path. A `literal` segment carries its fixed text (e.g. * `uploads`, `jr`, `photo.img`); a `wildcard` segment stands in for any single path segment * (a destructured param, a positional argument, a `mergeSlashPaths` variadic element) and * compares equal to a Firebase rules `{var}` / `{var=**}` path variable. */ export interface FoldedPathSegment { readonly kind: 'literal' | 'wildcard'; readonly value: string; } /** * The result of statically folding a `buildUploadPath` builder: an ordered list of * {@link FoldedPathSegment}s with leading/trailing/duplicate `/` collapsed. */ export interface FoldedUploadPath { readonly segments: readonly FoldedPathSegment[]; } /** * Outcome of {@link foldUploadPath}: either a folded path or a human-readable reason the * builder could not be reduced to a constant path template. The rule reports the reason via * the `unresolvablePolicyPath` diagnostic so authors either make the builder foldable or opt * out explicitly — the analyzer never guesses. */ export type FoldUploadPathResult = { readonly ok: true; readonly path: FoldedUploadPath; } | { readonly ok: false; readonly reason: string; }; /** * Resolves an imported binding (const declarator or function/arrow declaration) to its * declaration node in another module, plus the scope that node lives in so further * identifiers inside it resolve against that module's own imports/consts. * * Supplied by the rule when type information is available; absent in pure-AST contexts * (e.g. the unit tests), in which case cross-module references fold to "unresolvable". */ export interface ImportedBindingResolver { resolve(name: string, referenceNode: AstNode, fromScope: FoldScope): Maybe; } /** * A binding resolved to its declaration node plus the scope it belongs to. */ export interface ResolvedBinding { readonly node: AstNode; readonly scope: FoldScope; } /** * The lexical scope a node is folded in: the Program it belongs to and the import registry * for that module. Threaded through folding so an inlined cross-module function resolves its * own identifiers against its own module. */ export interface FoldScope { readonly program: AstNode; readonly importRegistry: ImportRegistry; readonly resolver: Maybe; } /** * Statically folds a `StorageFilePurposeUploadPolicy.buildUploadPath` builder to an abstract * path template. The builder is an arrow `(input) => ` whose destructured / * positional params become wildcards and whose body is a composition of string literals, * `const`s, `@dereekb/util` path combinators, and foldable single-`return` helper functions. * * @param builderNode - The `buildUploadPath` value node (arrow / function expression, possibly behind a type assertion). * @param scope - The lexical scope the builder lives in. * @returns The folded path, or a reason the builder is unresolvable. */ export declare function foldUploadPath(builderNode: AstNode, scope: FoldScope): FoldUploadPathResult; /** * Folds an expression to a concrete string literal value, reusing the same fragment folder the * path evaluator uses (literals, template literals, `const`s — local + cross-module — `+` * concatenation, modeled combinators, inlinable helpers). Returns null when the expression cannot * be reduced to a wildcard-free constant string, so callers preserve the sound "never guess" * contract. * * @param node - The expression node. * @param scope - The lexical scope the expression lives in. * @returns The folded string, or null when unresolvable. */ export declare function foldStringExpression(node: AstNode, scope: FoldScope): Maybe; /** * Folds an expression to a list of concrete strings: an inline array literal (each element folded * via {@link foldStringExpression}, spreads of statically-known lists expanded), or an identifier * resolving to such an array const (local or cross-module). Returns null when any element is * unfoldable, so a genuinely dynamic element (e.g. a function call) still surfaces as unresolvable. * * @param node - The expression node (e.g. an `allowedMimeTypes` value). * @param scope - The lexical scope the expression lives in. * @returns The folded string list, or null when unresolvable. */ export declare function foldStringArrayExpression(node: AstNode, scope: FoldScope): Maybe; /** * Folds a numeric expression to a number: literals, unary `-`/`+`, binary `*`/`+`/`-`/`/`, * type-assertion see-through, and identifiers resolving to a numeric `const` (local or * cross-module, read from the AST initializer). Returns null when any operand is unresolvable. * * @param node - The expression node (e.g. a `maxFileSizeBytes` value). * @param scope - The lexical scope the expression lives in. * @returns The folded number, or null when unresolvable. */ export declare function foldNumericExpression(node: AstNode, scope: FoldScope): Maybe; /** * Structurally compares a folded upload path against a Firebase rules match-path segment list * (`{var}` / `{var=**}` → wildcard, otherwise literal). Literal segments must match value; * wildcard segments compare equal to one another. * * @param folded - The folded upload path. * @param ruleSegments - The rules match-path segments. * @returns True when the two segment lists match position-for-position. */ export declare function foldedPathMatchesRuleSegments(folded: FoldedUploadPath, ruleSegments: readonly FoldedPathSegment[]): boolean; /** * Renders a folded path for diagnostics, e.g. `uploads/u/{*}/jr/{*}`. * * @param folded - The folded path. * @returns The display string. */ export declare function describeFoldedPath(folded: FoldedUploadPath): string;