import { Node, Expression, PropertyAssignment, ShorthandPropertyAssignment, GetAccessorDeclaration, CallExpression, SourceFile, JsxOpeningElement, JsxSelfClosingElement, JsxAttribute, TaggedTemplateExpression, Identifier, VariableDeclaration, ParameterDeclaration, FunctionDeclaration, EnumDeclaration, BindingElement, JsxSpreadAttribute } from 'ts-morph';
import { EvaluateOptions as EvaluateOptions$1 } from 'ts-evaluator';

interface WithNode {
    node: Node;
    stack: Node[];
}
interface ObjectType extends WithNode {
    type: 'object';
    value: EvaluatedObjectResult;
    isEmpty?: boolean;
}
type LiteralKind = 'array' | 'string' | 'number' | 'boolean' | 'null' | 'undefined';
interface LiteralType extends WithNode {
    type: 'literal';
    value: PrimitiveType;
    kind: LiteralKind;
}
interface MapType extends WithNode {
    type: 'map';
    value: MapTypeValue;
}
interface ArrayType extends WithNode {
    type: 'array';
    value: BoxNode[];
}
interface UnresolvableType extends WithNode {
    type: 'unresolvable';
}
interface ConditionalType extends WithNode {
    type: 'conditional';
    whenTrue: BoxNode;
    whenFalse: BoxNode;
}
/** -> Jsx boolean attribute <Box flex /> */
interface EmptyInitializerType extends WithNode {
    type: 'empty-initializer';
}
type BoxNodeDefinition = ObjectType | LiteralType | MapType | ArrayType | UnresolvableType | ConditionalType | EmptyInitializerType;
type BoxNode = BoxNodeObject | BoxNodeLiteral | BoxNodeMap | BoxNodeArray | BoxNodeUnresolvable | BoxNodeConditional | BoxNodeEmptyInitializer;
type MapTypeValue = Map<string, BoxNode>;
declare abstract class BoxNodeType$1<Definition extends BoxNodeDefinition = BoxNodeDefinition> {
    readonly type: Definition['type'];
    private readonly stack;
    private readonly node;
    constructor(definition: Definition);
    getNode(): Node;
    getStack(): Node[];
    getRange: () => {
        startPosition: number;
        startLineNumber: number;
        startColumn: number;
        endPosition: number;
        endLineNumber: number;
        endColumn: number;
    };
    toJSON(): {
        type: Definition["type"];
        value: any;
        node: string;
        line: number;
        column: number;
        endLineNumber: number;
        endColumn: number;
    };
    toString(): string;
}
declare class BoxNodeObject extends BoxNodeType$1<ObjectType> {
    value: ObjectType['value'];
    isEmpty: ObjectType['isEmpty'];
    constructor(definition: ObjectType);
}
declare class BoxNodeLiteral extends BoxNodeType$1<LiteralType> {
    value: LiteralType['value'];
    kind: LiteralType['kind'];
    constructor(definition: LiteralType);
}
declare class BoxNodeMap extends BoxNodeType$1<MapType> {
    value: MapType['value'];
    spreadConditions?: BoxNodeConditional[];
    constructor(definition: MapType);
    isRecipe: () => boolean;
}
declare class BoxNodeArray extends BoxNodeType$1<ArrayType> {
    value: ArrayType['value'];
    constructor(definition: ArrayType);
}
declare class BoxNodeUnresolvable extends BoxNodeType$1<UnresolvableType> {
}
declare class BoxNodeConditional extends BoxNodeType$1<ConditionalType> {
    whenTrue: ConditionalType['whenTrue'];
    whenFalse: ConditionalType['whenFalse'];
    constructor(definition: ConditionalType);
}
declare class BoxNodeEmptyInitializer extends BoxNodeType$1<EmptyInitializerType> {
}
declare const isBoxNode: (value: unknown) => value is BoxNode;

type PrimitiveType = string | number | boolean | null | undefined;
interface LiteralObject {
    [key: string]: any;
}
type SingleLiteralValue = PrimitiveType | LiteralObject;
type LiteralValue = SingleLiteralValue | SingleLiteralValue[];
interface EvaluatedObjectResult {
    [key: string]: LiteralValue;
}
interface ExtractedFunctionInstance {
    name: string;
    kind: 'call-expression';
    fromNode: () => CallExpression;
    box: BoxNodeArray;
}
interface ExtractedTaggedTemplateInstance {
    name: string;
    kind: 'tagged-template';
    fromNode: () => TaggedTemplateExpression;
    box: BoxNodeLiteral;
}
interface ExtractedFunctionResult {
    kind: 'function';
    nodesByProp: Map<string, BoxNode[]>;
    queryList: Array<ExtractedFunctionInstance | ExtractedTaggedTemplateInstance>;
}
interface ExtractedComponentInstance {
    name: string;
    fromNode: () => JsxOpeningElement | JsxSelfClosingElement | CallExpression;
    box: BoxNodeMap;
}
interface ExtractedComponentResult {
    kind: 'component';
    nodesByProp: Map<string, BoxNode[]>;
    queryList: ExtractedComponentInstance[];
}
type ExtractResultItem = ExtractedComponentResult | ExtractedFunctionResult;
type ExtractResultByName = Map<string, ExtractResultItem>;
interface MatchTagArgs {
    tagName: string;
    tagNode: JsxOpeningElement | JsxSelfClosingElement | CallExpression;
    isFactory: boolean;
}
interface MatchPropArgs {
    propName: string;
    propNode: JsxAttribute | PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration | undefined;
}
interface MatchFnArgs {
    fnName: string;
    fnNode: CallExpression;
}
interface MatchFnArguments {
    argNode: Node;
    index: number;
}
interface MatchFnPropArgs {
    propName: string;
    propNode: PropertyAssignment | ShorthandPropertyAssignment | GetAccessorDeclaration;
}
interface FunctionMatchers {
    matchFn: (element: MatchFnArgs) => boolean;
    matchArg: (arg: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnArguments) => boolean;
    matchProp: (prop: Pick<MatchFnArgs, 'fnName' | 'fnNode'> & MatchFnPropArgs) => boolean;
}
interface ComponentMatchers {
    matchTag: (element: MatchTagArgs) => boolean;
    matchProp: (prop: Pick<MatchTagArgs, 'tagName' | 'tagNode'> & MatchPropArgs) => boolean;
}
interface MatchTaggedTemplateArgs {
    fnName: string;
    taggedTemplateNode: TaggedTemplateExpression;
}
type MatchTaggedTemplate = (tag: MatchTaggedTemplateArgs) => boolean;
interface BoxContext {
    getEvaluateOptions?: (node: Expression, stack: Node[]) => Omit<EvaluateOptions, 'node' | 'policy'> | void;
    canEval?: (node: Expression, stack: Node[]) => boolean;
    tokens?: {
        view: {
            get: (path: string, fallback?: string | number) => string | undefined;
            getVar: (path: string, fallback?: string | number) => string | undefined;
        };
        isTokenFn?: (fnName: string) => boolean;
    };
    flags?: {
        skipEvaluate?: boolean;
        skipTraverseFiles?: boolean;
        skipConditions?: boolean;
    };
}
type EvaluateOptions = Omit<EvaluateOptions$1, 'node' | 'policy'>;
type ExtractOptions = BoxContext & {
    ast: SourceFile;
    components?: ComponentMatchers;
    functions?: FunctionMatchers;
    taggedTemplates?: {
        matchTaggedTemplate: MatchTaggedTemplate;
    };
};

declare function toBoxNode<Value extends PrimitiveType>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;
declare function toBoxNode<Value extends EvaluatedObjectResult>(value: Value, node: Node, stack: Node[]): BoxNodeObject;
declare function toBoxNode<Value extends PrimitiveType[]>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral[];
declare function toBoxNode<Value extends BoxNode | BoxNode[]>(value: Value, node: Node, stack: Node[]): Value;
declare function toBoxNode<Value extends LiteralValue>(value: Value, node: Node, stack: Node[]): Value extends unknown[] ? BoxNodeLiteral : Value extends PrimitiveType ? BoxNodeLiteral : BoxNodeObject;
declare function toBoxNode<Value extends PrimitiveType | BoxNode>(value: Value, node: Node, stack: Node[]): BoxNodeLiteral;

declare const box: {
    object(value: EvaluatedObjectResult, node: Node, stack: Node[]): BoxNodeObject;
    literal(value: PrimitiveType, node: Node, stack: Node[]): BoxNodeLiteral;
    map(value: MapTypeValue, node: Node, stack: Node[]): BoxNodeMap;
    array(value: BoxNode[], node: Node, stack: Node[]): BoxNodeArray;
    conditional(whenTrue: BoxNode, whenFalse: BoxNode, node: Node, stack: Node[]): BoxNodeConditional;
    from: typeof toBoxNode;
    objectToMap: (value: Record<string, unknown>, node: Node, stack: Node[]) => BoxNodeMap;
    emptyObject: (node: Node, stack: Node[]) => BoxNodeObject;
    emptyInitializer: (node: Node, stack: Node[]) => BoxNodeEmptyInitializer;
    unresolvable: (node: Node, stack: Node[]) => BoxNodeUnresolvable;
    fallback(node: BoxNode): BoxNode;
    /**
     * box.type === “object” -> object that was resolved using ts-evaluator, most likely from a
     * complex condition OR a simple CallExpression eval result, we don’t have access to individual
     * AST nodes here so we need the distinction
     */
    isObject(value: BoxNode | undefined): value is BoxNodeObject;
    isLiteral(value: BoxNode | undefined): value is BoxNodeLiteral;
    /**
     * box.type === “map” -> basically any object that was statically analyzable, we store each
     * prop + value in a Map
     */
    isMap(value: BoxNode | undefined): value is BoxNodeMap;
    isRecipe(value: BoxNode | undefined): value is BoxNodeMap;
    isArray(value: BoxNode | undefined): value is BoxNodeArray;
    isUnresolvable(value: BoxNode | undefined): value is BoxNodeUnresolvable;
    isConditional(value: BoxNode | undefined): value is BoxNodeConditional;
    isEmptyInitializer(value: BoxNode | undefined): value is BoxNodeEmptyInitializer;
    isNumberLiteral(node: BoxNode | undefined): node is BoxNodeLiteral;
    hasValue: (node: BoxNode | undefined) => node is BoxNodeLiteral | BoxNodeObject | BoxNodeMap | BoxNodeArray;
};

type MatchProp$1 = (prop: MatchFnPropArgs) => boolean;
type MatchArg = (prop: MatchFnArgs & MatchFnArguments) => boolean;
declare const extractCallExpressionArguments: (node: CallExpression, ctx: BoxContext, matchProp?: MatchProp$1, matchArg?: MatchArg) => BoxNodeArray;

declare const extract: ({ ast, ...ctx }: ExtractOptions) => ExtractResultByName;

declare function getDeclarationFor(node: Identifier, stack: Node[], ctx: BoxContext): VariableDeclaration | ParameterDeclaration | FunctionDeclaration | EnumDeclaration | BindingElement | undefined;
declare function findIdentifierValueDeclaration(identifier: Identifier, stack: Node[], ctx: BoxContext, visitedsWithStack?: WeakMap<Node, Node[]>): ReturnType<typeof getDeclarationFor> | undefined;

declare const getNodeRange: (node: Node) => {
    startPosition: number;
    startLineNumber: number;
    startColumn: number;
    endPosition: number;
    endLineNumber: number;
    endColumn: number;
};
type NodeRange = ReturnType<typeof getNodeRange>;

declare const extractJsxAttribute: (jsxAttribute: JsxAttribute, ctx: BoxContext) => BoxNode | undefined;

declare const extractJsxElementProps: (node: JsxOpeningElement | JsxSelfClosingElement, ctx: BoxContext) => {
    name: string;
    props: Map<string, BoxNode>;
};

type MaybeBoxNodeReturn = BoxNode | undefined;
declare function maybeBoxNode(node: Node, stack: Node[], ctx: BoxContext, matchProp?: (prop: MatchFnPropArgs) => boolean): MaybeBoxNodeReturn;
declare const maybeIdentifierValue: (identifier: Identifier, _stack: Node[], ctx: BoxContext) => BoxNode;

type MatchProp = (prop: MatchFnPropArgs | MatchPropArgs) => boolean;
declare const extractJsxSpreadAttributeValues: (node: JsxSpreadAttribute, ctx: BoxContext, matchProp: MatchProp) => MaybeBoxNodeReturn;

type BoxNodeType = BoxNode | BoxNode[] | undefined;
type CacheMap = WeakMap<BoxNode, Unboxed>;
interface UnboxContext {
    path: string[];
    parent: BoxNode | undefined;
    cache: CacheMap;
    /** @example <ColorBox color={unresolvableIdentifier ? "light.100" : "dark.200" } /> */
    conditions: LiteralObject[];
    /** @example <ColorBox {...(someCondition && { color: "blue.100" })} /> */
    spreadConditions: LiteralObject[];
}
interface Unboxed {
    raw: LiteralObject;
    conditions: LiteralObject[];
    spreadConditions: LiteralObject[];
}
declare const unbox: (node: BoxNodeType, ctx?: Pick<UnboxContext, "cache">) => Unboxed;

export { type BoxContext, type BoxNode, BoxNodeArray, BoxNodeConditional, BoxNodeEmptyInitializer, BoxNodeLiteral, BoxNodeMap, BoxNodeObject, BoxNodeUnresolvable, type EvaluateOptions, type ExtractOptions, type ExtractResultByName, type ExtractResultItem, type ExtractedComponentInstance, type ExtractedComponentResult, type ExtractedFunctionInstance, type ExtractedFunctionResult, type NodeRange, type PrimitiveType, type Unboxed, box, extract, extractCallExpressionArguments, extractJsxAttribute, extractJsxElementProps, extractJsxSpreadAttributeValues, findIdentifierValueDeclaration, isBoxNode, maybeBoxNode, maybeIdentifierValue, unbox };
