"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getComponentMeta = getComponentMeta;
const core = __importStar(require("@vue/language-core"));
const helpers_1 = require("./helpers");
const schemaResolvers_1 = require("./schemaResolvers");
const scriptSetup_1 = require("./scriptSetup");
const vnodeEventRE = /^onVnode[A-Z]/;
function getComponentMeta(ts, typeChecker, printer, language, getSourceScript, componentNode, componentType, options, deprecatedOptions = { noDeclarations: true, rawType: false }) {
    const componentSymbol = typeChecker.getSymbolAtLocation(componentNode);
    let componentFile = componentNode.getSourceFile();
    if (componentSymbol) {
        const symbol = componentSymbol.flags & ts.SymbolFlags.Alias
            ? typeChecker.getAliasedSymbol(componentSymbol)
            : componentType.symbol;
        const declaration = symbol?.valueDeclaration ?? symbol?.declarations?.[0];
        if (declaration) {
            componentFile = declaration.getSourceFile();
            componentNode = declaration;
        }
    }
    let name;
    let description;
    let type;
    let props;
    let events;
    let slots;
    let exposed;
    const meta = {
        get name() {
            return name ?? (name = getName());
        },
        get description() {
            return description ?? (description = getDescription());
        },
        get type() {
            return type ?? (type = getType());
        },
        get props() {
            return props ?? (props = getProps());
        },
        get events() {
            return events ?? (events = getEvents());
        },
        get slots() {
            return slots ?? (slots = getSlots());
        },
        get exposed() {
            return exposed ?? (exposed = getExposed());
        },
    };
    return meta;
    function getType() {
        return (0, helpers_1.inferComponentType)(componentType) ?? 0;
    }
    function getProps() {
        const propsType = (0, helpers_1.inferComponentProps)(typeChecker, componentType);
        if (!propsType) {
            return [];
        }
        let result = [];
        const properties = propsType.getProperties();
        const eventProps = new Set(meta.events.map(event => `on${event.name.charAt(0).toUpperCase()}${event.name.slice(1)}`));
        result = properties
            .map(prop => {
            const { resolveNestedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
            return resolveNestedProperties(prop);
        })
            .filter((prop) => !!prop && !eventProps.has(prop.name));
        const defaults = (0, scriptSetup_1.getDefaultsFromScriptSetup)(ts, printer, getSourceScript(componentFile.fileName));
        for (const prop of result) {
            if (vnodeEventRE.test(prop.name)) {
                prop.name = 'onVue:' + prop.name['onVnode'.length]?.toLowerCase() + prop.name.slice('onVnode'.length + 1);
            }
            prop.default ??= defaults?.get(prop.name);
        }
        return result;
    }
    function getEvents() {
        const emitType = (0, helpers_1.inferComponentEmit)(typeChecker, componentType);
        if (emitType) {
            const calls = emitType.getCallSignatures();
            return calls.map(call => {
                const { resolveEventSignature, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
                return resolveEventSignature(call);
            }).filter(event => event.name);
        }
        return [];
    }
    function getSlots() {
        const slotsType = (0, helpers_1.inferComponentSlots)(typeChecker, componentType);
        if (slotsType) {
            const properties = slotsType.getProperties();
            return properties.map(prop => {
                const { resolveSlotProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
                return resolveSlotProperties(prop);
            });
        }
        return [];
    }
    function getExposed() {
        const exposedType = (0, helpers_1.inferComponentExposed)(typeChecker, componentType);
        if (exposedType) {
            const propsType = (0, helpers_1.inferComponentProps)(typeChecker, componentType);
            const propsProperties = propsType?.getProperties() ?? [];
            const properties = exposedType.getProperties().filter(prop => 
            // only exposed props will have at least one declaration and no valueDeclaration
            prop.declarations?.length
                && !prop.valueDeclaration
                // Cross-check with props to avoid including props here
                && (!propsProperties.length || !propsProperties.some(({ name }) => name === prop.name))
                // Exclude $slots
                && prop.name !== '$slots');
            return properties.map(prop => {
                const { resolveExposedProperties, } = (0, schemaResolvers_1.createSchemaResolvers)(ts, typeChecker, printer, language, getSourceScript, options, deprecatedOptions);
                return resolveExposedProperties(prop);
            });
        }
        return [];
    }
    function getName() {
        let decl = componentNode;
        // const __VLS_export = ...
        const text = componentFile.text.slice(decl.pos, decl.end);
        if (text.includes(core.names.export)) {
            ts.forEachChild(componentFile, child2 => {
                if (ts.isVariableStatement(child2)) {
                    for (const { name, initializer } of child2.declarationList.declarations) {
                        if (name.getText() === core.names.export && initializer) {
                            decl = initializer;
                        }
                    }
                }
            });
        }
        return core.parseOptionsFromExtression(ts, decl, componentFile)?.name?.node.text;
    }
    function getDescription() {
        // Try to get JSDoc comments from the node using TypeScript API
        const jsDocComments = ts.getJSDocCommentsAndTags(componentNode);
        for (const jsDoc of jsDocComments) {
            if (ts.isJSDoc(jsDoc) && jsDoc.comment) {
                // Handle both string and array of comment parts
                if (typeof jsDoc.comment === 'string') {
                    return jsDoc.comment;
                }
                else if (Array.isArray(jsDoc.comment)) {
                    return jsDoc.comment.map(part => part.text || '').join('');
                }
            }
        }
        // Fallback to symbol documentation
        const symbol = typeChecker.getSymbolAtLocation(componentNode);
        if (symbol) {
            const description = ts.displayPartsToString(symbol.getDocumentationComment(typeChecker));
            return description || undefined;
        }
    }
}
//# sourceMappingURL=componentMeta.js.map