"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JsOrTsComponentInfoProvider = void 0;
const typescript_1 = __importDefault(require("typescript"));
const utils_1 = require("../../utils");
const utils_2 = require("./features/utils");
class JsOrTsComponentInfoProvider {
    constructor(typeChecker, classType, useSvelte5PlusPropsParameter = false) {
        this.typeChecker = typeChecker;
        this.classType = classType;
        this.useSvelte5PlusPropsParameter = useSvelte5PlusPropsParameter;
    }
    getEvents() {
        const eventType = this.getType(this.useSvelte5PlusPropsParameter ? '$$events' : '$$events_def');
        if (!eventType) {
            return [];
        }
        return this.mapPropertiesOfType(eventType);
    }
    getSlotLets(slot = 'default') {
        const slotType = this.getType(this.useSvelte5PlusPropsParameter ? '$$slots' : '$$slot_def');
        if (!slotType) {
            return [];
        }
        const slotLets = slotType.getProperties().find((prop) => prop.name === slot);
        if (!slotLets?.valueDeclaration) {
            return [];
        }
        const slotLetsType = this.typeChecker.getTypeOfSymbolAtLocation(slotLets, slotLets.valueDeclaration);
        return this.mapPropertiesOfType(slotLetsType);
    }
    getProps() {
        if (!this.useSvelte5PlusPropsParameter) {
            const props = this.getType('$$prop_def');
            if (!props) {
                return [];
            }
            return this.mapPropertiesOfType(props);
        }
        return this.mapPropertiesOfType(this.classType).filter((prop) => !prop.name.startsWith('$$'));
    }
    getType(classProperty) {
        const symbol = this.classType.getProperty(classProperty);
        if (!symbol?.valueDeclaration) {
            return null;
        }
        return this.typeChecker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
    }
    mapPropertiesOfType(type) {
        return type
            .getProperties()
            .map((prop) => {
            // type would still be correct when there're multiple declarations
            const declaration = prop.valueDeclaration ??
                prop.declarations?.[0] ??
                // very complex types are hidden on this thing for some reason
                prop?.links?.mappedType?.declaration;
            if (!declaration) {
                return;
            }
            return {
                name: prop.name,
                type: this.typeChecker.typeToString(this.typeChecker.getTypeOfSymbolAtLocation(prop, declaration)),
                doc: typescript_1.default.displayPartsToString(prop.getDocumentationComment(this.typeChecker))
            };
        })
            .filter(utils_1.isNotNullOrUndefined);
    }
    /**
     * The result of this shouldn't be cached as it could lead to memory leaks. The type checker
     * could become old and then multiple versions of it could exist.
     */
    static create(lang, def, isSvelte5Plus) {
        const program = lang.getProgram();
        const sourceFile = program?.getSourceFile(def.fileName);
        if (!program || !sourceFile) {
            return null;
        }
        const defIdentifier = (0, utils_2.findContainingNode)(sourceFile, def.textSpan, typescript_1.default.isIdentifier);
        if (!defIdentifier) {
            return null;
        }
        const typeChecker = program.getTypeChecker();
        const componentSymbol = typeChecker.getSymbolAtLocation(defIdentifier);
        if (!componentSymbol) {
            return null;
        }
        const type = typeChecker.getTypeOfSymbolAtLocation(componentSymbol, defIdentifier);
        if (type.isClass()) {
            return new JsOrTsComponentInfoProvider(typeChecker, type);
        }
        const constructorSignatures = type.getConstructSignatures();
        if (constructorSignatures.length === 1) {
            return new JsOrTsComponentInfoProvider(typeChecker, constructorSignatures[0].getReturnType());
        }
        if (!isSvelte5Plus) {
            return null;
        }
        const signatures = type.getCallSignatures();
        if (signatures.length !== 1) {
            return null;
        }
        const propsParameter = signatures[0].parameters[1];
        if (!propsParameter) {
            return null;
        }
        const propsParameterType = typeChecker.getTypeOfSymbol(propsParameter);
        return new JsOrTsComponentInfoProvider(typeChecker, propsParameterType, 
        /** useSvelte5PlusPropsParameter */ true);
    }
}
exports.JsOrTsComponentInfoProvider = JsOrTsComponentInfoProvider;
//# sourceMappingURL=ComponentInfoProvider.js.map