"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.createCheckerBase = createCheckerBase;
exports.getExport = getExport;
const typescript_1 = require("@volar/typescript");
const core = __importStar(require("@vue/language-core"));
const componentMeta_1 = require("./componentMeta");
function createCheckerBase(ts, getConfigAndFiles, checkerOptions, rootPath) {
    let [{ vueOptions, options, projectReferences }, fileNames] = getConfigAndFiles();
    /**
     * Used to lookup if a file is referenced.
     */
    let fileNamesSet = new Set(fileNames.map(path => path.replace(/\\/g, '/')));
    let projectVersion = 0;
    const projectHost = {
        getCurrentDirectory: () => rootPath,
        getProjectVersion: () => projectVersion.toString(),
        getCompilationSettings: () => options,
        getScriptFileNames: () => [...fileNamesSet],
        getProjectReferences: () => projectReferences,
    };
    const scriptSnapshots = new Map();
    const vueLanguagePlugin = core.createVueLanguagePlugin(ts, projectHost.getCompilationSettings(), vueOptions, id => id);
    const language = core.createLanguage([
        vueLanguagePlugin,
        {
            getLanguageId(fileName) {
                return (0, typescript_1.resolveFileLanguageId)(fileName);
            },
        },
    ], new core.FileMap(ts.sys.useCaseSensitiveFileNames), fileName => {
        let snapshot = scriptSnapshots.get(fileName);
        if (!scriptSnapshots.has(fileName)) {
            const fileText = ts.sys.readFile(fileName);
            if (fileText !== undefined) {
                scriptSnapshots.set(fileName, ts.ScriptSnapshot.fromString(fileText));
            }
            else {
                scriptSnapshots.set(fileName, undefined);
            }
        }
        snapshot = scriptSnapshots.get(fileName);
        if (snapshot) {
            language.scripts.set(fileName, snapshot);
        }
        else {
            language.scripts.delete(fileName);
        }
    });
    const { languageServiceHost } = (0, typescript_1.createLanguageServiceHost)(ts, ts.sys, language, s => s, projectHost);
    const tsLs = ts.createLanguageService(languageServiceHost);
    const printer = ts.createPrinter({
        ...checkerOptions.printer,
        // @ts-expect-error internal option to prevent unicode-escaping non-ASCII characters
        neverAsciiEscape: true,
    });
    const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost);
    if (checkerOptions.forceUseTs ?? true) {
        languageServiceHost.getScriptKind = fileName => {
            const scriptKind = getScriptKind(fileName);
            if (vueOptions.extensions.some(ext => fileName.endsWith(ext))) {
                if (scriptKind === ts.ScriptKind.JS) {
                    return ts.ScriptKind.TS;
                }
                if (scriptKind === ts.ScriptKind.JSX) {
                    return ts.ScriptKind.TSX;
                }
            }
            return scriptKind;
        };
    }
    return {
        getExportNames,
        getComponentMeta(fileName, exportName = 'default') {
            fileName = fileName.replace(/\\/g, '/');
            const [program, sourceFile] = getProgramAndFile(fileName);
            const componentNode = getExport(ts, program, sourceFile, exportName);
            if (!componentNode) {
                throw new Error(`Export '${exportName}' not found in '${sourceFile.fileName}'.`);
            }
            const checker = program.getTypeChecker();
            const componentType = checker.getTypeAtLocation(componentNode);
            return (0, componentMeta_1.getComponentMeta)(ts, checker, printer, language, fileName => language.scripts.get(fileName), componentNode, componentType, checkerOptions.schema ?? false, {
                noDeclarations: checkerOptions.noDeclarations ?? true,
                rawType: checkerOptions.rawType ?? false,
            });
        },
        updateFile(fileName, text) {
            fileName = fileName.replace(/\\/g, '/');
            scriptSnapshots.set(fileName, ts.ScriptSnapshot.fromString(text));
            // Ensure the file is referenced
            fileNamesSet.add(fileName);
            projectVersion++;
        },
        deleteFile(fileName) {
            fileName = fileName.replace(/\\/g, '/');
            fileNamesSet.delete(fileName);
            projectVersion++;
        },
        reload() {
            [{ vueOptions, options, projectReferences }, fileNames] = getConfigAndFiles();
            fileNamesSet = new Set(fileNames.map(path => path.replace(/\\/g, '/')));
            this.clearCache();
        },
        clearCache() {
            scriptSnapshots.clear();
            projectVersion++;
        },
        getProgram() {
            return tsLs.getProgram();
        },
    };
    function getProgramAndFile(componentPath) {
        const program = tsLs.getProgram();
        const sourceFile = program.getSourceFile(componentPath);
        if (!sourceFile) {
            throw new Error(`'${componentPath}' is not part of the project. `
                + `Use a tsconfig that includes it, or call \`updateFile()\` to add it.`);
        }
        return [program, sourceFile];
    }
    function getExportNames(componentPath) {
        const [program, sourceFile] = getProgramAndFile(componentPath);
        return getExports(program, sourceFile).map(e => e.getName());
    }
}
function getExport(ts, program, sourceFile, exportName) {
    const exports = getExports(program, sourceFile);
    const symbol = exports.find(e => e.getName() === exportName);
    if (symbol?.valueDeclaration) {
        const decl = symbol.valueDeclaration;
        if (ts.isExportAssignment(decl)) {
            return decl.expression;
        }
        if (ts.isVariableDeclaration(decl)) {
            return decl.initializer;
        }
    }
}
function getExports(program, sourceFile) {
    const typeChecker = program.getTypeChecker();
    const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
    return moduleSymbol ? typeChecker.getExportsOfModule(moduleSymbol) : [];
}
//# sourceMappingURL=checker.js.map