"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSvelteFilePath = isSvelteFilePath;
exports.isVirtualSvelteFilePath = isVirtualSvelteFilePath;
exports.toRealSvelteFilePath = toRealSvelteFilePath;
exports.toVirtualSvelteFilePath = toVirtualSvelteFilePath;
exports.ensureRealSvelteFilePath = ensureRealSvelteFilePath;
exports.isNotNullOrUndefined = isNotNullOrUndefined;
exports.isInGeneratedCode = isInGeneratedCode;
exports.isNoTextSpanInGeneratedCode = isNoTextSpanInGeneratedCode;
exports.replaceDeep = replaceDeep;
exports.getConfigPathForProject = getConfigPathForProject;
exports.isStoreVariableIn$storeDeclaration = isStoreVariableIn$storeDeclaration;
exports.get$storeOffsetOf$storeDeclaration = get$storeOffsetOf$storeDeclaration;
exports.findNodeAtSpan = findNodeAtSpan;
exports.findNodeAtPosition = findNodeAtPosition;
exports.isTopLevelExport = isTopLevelExport;
exports.isGeneratedSvelteComponentName = isGeneratedSvelteComponentName;
exports.offsetOfGeneratedComponentExport = offsetOfGeneratedComponentExport;
exports.gatherDescendants = gatherDescendants;
exports.findIdentifier = findIdentifier;
exports.getProjectDirectory = getProjectDirectory;
exports.hasNodeModule = hasNodeModule;
exports.isSvelteProject = isSvelteProject;
exports.importSvelteCompiler = importSvelteCompiler;
exports.getProjectParsedCommandLine = getProjectParsedCommandLine;
const path_1 = require("path");
function isSvelteFilePath(filePath) {
    return filePath.endsWith('.svelte');
}
function isVirtualSvelteFilePath(filePath) {
    return filePath.endsWith('.d.svelte.ts');
}
function toRealSvelteFilePath(filePath) {
    return filePath.slice(0, -11 /* 'd.svelte.ts'.length */) + 'svelte';
}
function toVirtualSvelteFilePath(svelteFilePath) {
    return isVirtualSvelteFilePath(svelteFilePath)
        ? svelteFilePath
        : svelteFilePath.slice(0, -6 /* 'svelte'.length */) + 'd.svelte.ts';
}
function ensureRealSvelteFilePath(filePath) {
    return isVirtualSvelteFilePath(filePath) ? toRealSvelteFilePath(filePath) : filePath;
}
function isNotNullOrUndefined(val) {
    return val !== undefined && val !== null;
}
/**
 * Checks if this a section that should be completely ignored
 * because it's purely generated.
 */
function isInGeneratedCode(text, start, end) {
    const lineStart = text.lastIndexOf('\n', start);
    const lineEnd = text.indexOf('\n', end);
    const lastStart = text.substring(lineStart, start).lastIndexOf('/*Ωignore_startΩ*/');
    const lastEnd = text.substring(lineStart, start).lastIndexOf('/*Ωignore_endΩ*/');
    return lastStart > lastEnd && text.substring(end, lineEnd).includes('/*Ωignore_endΩ*/');
}
/**
 * Checks that this isn't a text span that should be completely ignored
 * because it's purely generated.
 */
function isNoTextSpanInGeneratedCode(text, span) {
    return !isInGeneratedCode(text, span.start, span.start + span.length);
}
/**
 * Replace all occurrences of a string within an object with another string,
 */
function replaceDeep(obj, searchStr, replacementStr) {
    return _replaceDeep(obj);
    function _replaceDeep(_obj) {
        if (typeof _obj === 'string') {
            return _obj.replace(searchStr, replacementStr);
        }
        if (Array.isArray(_obj)) {
            return _obj.map((entry) => _replaceDeep(entry));
        }
        if (typeof _obj === 'object') {
            return Object.keys(_obj).reduce((_o, key) => {
                _o[key] = _replaceDeep(_obj[key]);
                return _o;
            }, {});
        }
        return _obj;
    }
}
function getConfigPathForProject(project) {
    return (project.canonicalConfigFilePath ??
        project.getCompilerOptions().configFilePath);
}
function isStoreVariableIn$storeDeclaration(text, varStart) {
    return (text.lastIndexOf('__sveltets_2_store_get(', varStart) ===
        varStart - '__sveltets_2_store_get('.length);
}
function get$storeOffsetOf$storeDeclaration(text, storePosition) {
    return text.lastIndexOf(' =', storePosition) - 1;
}
/**
 * Finds node exactly matching span {start, length}.
 */
function findNodeAtSpan(node, span, predicate) {
    const { start, length } = span;
    const end = start + length;
    return node.forEachChild((child) => {
        const childStart = child.getStart();
        if (end <= childStart) {
            return;
        }
        const childEnd = child.getEnd();
        if (start >= childEnd) {
            return;
        }
        if (start === childStart && end === childEnd) {
            if (!predicate) {
                return child;
            }
            if (predicate(child)) {
                return child;
            }
        }
        const foundInChildren = findNodeAtSpan(child, span, predicate);
        if (foundInChildren) {
            return foundInChildren;
        }
    });
}
/**
 * Finds node somewhere at position.
 */
function findNodeAtPosition(node, pos, predicate) {
    return node.forEachChild((child) => {
        const childStart = child.getStart();
        if (pos < childStart) {
            return;
        }
        const childEnd = child.getEnd();
        if (pos > childEnd) {
            return;
        }
        const foundInChildren = findNodeAtPosition(child, pos, predicate);
        if (foundInChildren) {
            return foundInChildren;
        }
        if (!predicate) {
            return child;
        }
        if (predicate(child)) {
            return child;
        }
    });
}
/**
 * True if is `export const/let/function`
 */
function isTopLevelExport(ts, node, source) {
    return ((ts.isVariableStatement(node) && source.statements.includes(node)) ||
        (ts.isIdentifier(node) &&
            node.parent &&
            ts.isVariableDeclaration(node.parent) &&
            source.statements.includes(node.parent?.parent?.parent)) ||
        (ts.isIdentifier(node) &&
            node.parent &&
            ts.isFunctionDeclaration(node.parent) &&
            source.statements.includes(node.parent)));
}
const COMPONENT_SUFFIX = '__SvelteComponent_';
function isGeneratedSvelteComponentName(className) {
    return className.endsWith(COMPONENT_SUFFIX);
}
function offsetOfGeneratedComponentExport(snapshot) {
    return snapshot.getText().lastIndexOf(COMPONENT_SUFFIX);
}
function gatherDescendants(node, predicate, dest = []) {
    if (predicate(node)) {
        dest.push(node);
    }
    else {
        node.forEachChild((child) => {
            gatherDescendants(child, predicate, dest);
        });
    }
    return dest;
}
function findIdentifier(ts, node) {
    if (ts.isIdentifier(node)) {
        return node;
    }
    if (ts.isFunctionDeclaration(node)) {
        return node.name;
    }
    while (node) {
        if (ts.isIdentifier(node)) {
            return node;
        }
        if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
            return node.name;
        }
        node = node.parent;
    }
}
function getProjectDirectory(project) {
    const compilerOptions = project.getCompilerOptions();
    if (typeof compilerOptions.configFilePath === 'string') {
        return (0, path_1.dirname)(compilerOptions.configFilePath);
    }
    const packageJsonPath = (0, path_1.join)(project.getCurrentDirectory(), 'package.json');
    return project.fileExists(packageJsonPath) ? project.getCurrentDirectory() : undefined;
}
function hasNodeModule(startPath, module) {
    try {
        const hasModule = require.resolve(module, { paths: [startPath] });
        return hasModule;
    }
    catch (e) {
        // If require.resolve fails, we end up here, which can be either because the package is not found,
        // or (in case of things like SvelteKit) the package is found but the package.json is not exported.
        return e?.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED';
    }
}
function isSvelteProject(project) {
    // internal api, the way to check requires checking the files config in tsconfig.json
    // so we can't reimplement it without reading the tsconfig.json again
    // The solution project is mostly just a container we don't need to patch it
    // and having any files in this project cause TSServer to send config error while it originally won't
    if (project.isSolution?.()) {
        // In TypeScript before 5.7, the project files were added later than plugin loading
        // so we need to also check if the parsedCommandLine includes any files
        const parsedCommandLine = getProjectParsedCommandLine(project);
        if (parsedCommandLine?.fileNames.length === 0) {
            return false;
        }
    }
    const projectDirectory = getProjectDirectory(project);
    if (projectDirectory) {
        return hasNodeModule(projectDirectory, 'svelte');
    }
    const packageJsons = project
        .readDirectory(project.getCurrentDirectory(), ['.json'], ['node_modules', 'dist', 'build'], ['**/package.json'], 
    // assuming structure like packages/projectName
    3)
        // in case some other plugin patched readDirectory in a weird way
        .filter((file) => file.endsWith('package.json') && !hasConfigInConjunction(file, project));
    return packageJsons.some((packageJsonPath) => hasNodeModule((0, path_1.dirname)(packageJsonPath), 'svelte'));
}
function hasConfigInConjunction(packageJsonPath, project) {
    const dir = (0, path_1.dirname)(packageJsonPath);
    return (project.fileExists((0, path_1.join)(dir, 'tsconfig.json')) ||
        project.fileExists((0, path_1.join)(dir, 'jsconfig.json')));
}
function importSvelteCompiler(fromPath) {
    if (!fromPath)
        return undefined;
    try {
        const sveltePath = require.resolve('svelte/compiler', { paths: [fromPath] });
        const compiler = require(sveltePath);
        if (compiler.VERSION.split('.')[0] === '3') {
            // use built-in version for Svelte 3
            return undefined;
        }
        return compiler;
    }
    catch (e) {
        // ignore
    }
}
/**
 * This call the ConfiguredProject.getParsedCommandLine
 * where it'll try to load the cached version of the parsedCommandLine
 */
function getProjectParsedCommandLine(project) {
    const configPath = getConfigPathForProject(project);
    const parsedCommandLine = project.getParsedCommandLine?.(configPath);
    return parsedCommandLine;
}
//# sourceMappingURL=utils.js.map