"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractVueComponents = void 0;
const csf3_1 = require("@previewjs/csf3");
const type_analyzer_1 = require("@previewjs/type-analyzer");
const typescript_1 = __importDefault(require("typescript"));
const infer_component_name_1 = require("./infer-component-name");
function extractVueComponents(resolver, absoluteFilePath) {
    var _a, _b, _c;
    const sourceFile = resolver.sourceFile(absoluteFilePath);
    if (!sourceFile) {
        return [];
    }
    const functions = [];
    for (const statement of sourceFile.statements) {
        if (typescript_1.default.isExportAssignment(statement)) {
            if (typescript_1.default.isIdentifier(statement.expression)) {
                // Avoid duplicates.
                continue;
            }
            functions.push(["default", statement, statement.expression]);
        }
        else if (typescript_1.default.isVariableStatement(statement)) {
            for (const declaration of statement.declarationList.declarations) {
                if (!typescript_1.default.isIdentifier(declaration.name) || !declaration.initializer) {
                    continue;
                }
                functions.push([
                    declaration.name.text,
                    statement,
                    declaration.initializer,
                ]);
            }
        }
        else if (typescript_1.default.isFunctionDeclaration(statement)) {
            const isDefaultExport = !!((_a = statement.modifiers) === null || _a === void 0 ? void 0 : _a.find((m) => m.kind === typescript_1.default.SyntaxKind.ExportKeyword)) &&
                !!((_b = statement.modifiers) === null || _b === void 0 ? void 0 : _b.find((m) => m.kind === typescript_1.default.SyntaxKind.DefaultKeyword));
            const name = (_c = statement.name) === null || _c === void 0 ? void 0 : _c.text;
            if (isDefaultExport || name) {
                functions.push([name || "default", statement, statement]);
            }
        }
    }
    const storiesDefaultComponent = (0, csf3_1.extractDefaultComponent)(sourceFile);
    const resolvedStoriesComponent = storiesDefaultComponent
        ? (0, csf3_1.resolveComponent)(resolver.checker, storiesDefaultComponent)
        : null;
    const components = [];
    const nameToExportedName = type_analyzer_1.helpers.extractExportedNames(sourceFile);
    const args = type_analyzer_1.helpers.extractArgs(sourceFile);
    // TODO: Handle JSX and Storybook stories.
    const analysis = {
        propsType: type_analyzer_1.UNKNOWN_TYPE,
        types: {},
    };
    for (const [name, statement, node] of functions) {
        const hasArgs = !!args[name];
        const isExported = name === "default" || !!nameToExportedName[name];
        const signature = extractVueComponent(resolver.checker, node, hasArgs);
        if (signature) {
            components.push({
                absoluteFilePath,
                name,
                offsets: [[statement.getFullStart(), statement.getEnd()]],
                info: storiesDefaultComponent && hasArgs && isExported
                    ? {
                        kind: "story",
                        associatedComponent: resolvedStoriesComponent,
                    }
                    : {
                        kind: "component",
                        exported: isExported,
                        analyze: async () => analysis,
                    },
            });
        }
    }
    return [...components, ...(0, csf3_1.extractCsf3Stories)(resolver, sourceFile)].map((c) => ({
        ...c,
        info: c.info.kind === "story"
            ? {
                kind: "story",
                associatedComponent: c.info.associatedComponent
                    ? transformVirtualTsVueFile(c.info.associatedComponent)
                    : null,
            }
            : c.info,
    }));
}
exports.extractVueComponents = extractVueComponents;
function transformVirtualTsVueFile({ absoluteFilePath, name, }) {
    if (absoluteFilePath.endsWith(".vue.ts")) {
        absoluteFilePath = absoluteFilePath.substring(0, absoluteFilePath.length - 3);
        name = (0, infer_component_name_1.inferComponentNameFromVuePath)(absoluteFilePath);
    }
    return { absoluteFilePath, name };
}
function extractVueComponent(checker, node, hasArgs) {
    const type = checker.getTypeAtLocation(node);
    for (const callSignature of type.getCallSignatures()) {
        const returnType = callSignature.getReturnType();
        if (isJsxElement(returnType)) {
            // JSX component.
            return callSignature;
        }
        if (returnType.getProperty("template") || hasArgs) {
            // This is a story.
            return callSignature;
        }
    }
    return null;
}
const jsxElementTypes = new Set(["Element"]);
function isJsxElement(type) {
    var _a;
    if (type.isUnion()) {
        for (const subtype of type.types) {
            if (isJsxElement(subtype)) {
                return true;
            }
        }
    }
    return jsxElementTypes.has((_a = type.symbol) === null || _a === void 0 ? void 0 : _a.getEscapedName().toString());
}
