"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.DiagnosticsProviderImpl = exports.DiagnosticCode = void 0;
exports.mapAndFilterDiagnostics = mapAndFilterDiagnostics;
const typescript_1 = __importStar(require("typescript"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../../lib/documents");
const utils_1 = require("../utils");
const utils_2 = require("./utils");
const utils_3 = require("../../../utils");
const svelte_ast_utils_1 = require("../svelte-ast-utils");
const svelte2tsx_1 = require("svelte2tsx");
var DiagnosticCode;
(function (DiagnosticCode) {
    DiagnosticCode[DiagnosticCode["MODIFIERS_CANNOT_APPEAR_HERE"] = 1184] = "MODIFIERS_CANNOT_APPEAR_HERE";
    DiagnosticCode[DiagnosticCode["USED_BEFORE_ASSIGNED"] = 2454] = "USED_BEFORE_ASSIGNED";
    DiagnosticCode[DiagnosticCode["JSX_ELEMENT_DOES_NOT_SUPPORT_ATTRIBUTES"] = 2607] = "JSX_ELEMENT_DOES_NOT_SUPPORT_ATTRIBUTES";
    DiagnosticCode[DiagnosticCode["CANNOT_BE_USED_AS_JSX_COMPONENT"] = 2786] = "CANNOT_BE_USED_AS_JSX_COMPONENT";
    DiagnosticCode[DiagnosticCode["NOOP_IN_COMMAS"] = 2695] = "NOOP_IN_COMMAS";
    DiagnosticCode[DiagnosticCode["NEVER_READ"] = 6133] = "NEVER_READ";
    DiagnosticCode[DiagnosticCode["ALL_IMPORTS_UNUSED"] = 6192] = "ALL_IMPORTS_UNUSED";
    DiagnosticCode[DiagnosticCode["UNUSED_LABEL"] = 7028] = "UNUSED_LABEL";
    DiagnosticCode[DiagnosticCode["DUPLICATED_JSX_ATTRIBUTES"] = 17001] = "DUPLICATED_JSX_ATTRIBUTES";
    DiagnosticCode[DiagnosticCode["DUPLICATE_IDENTIFIER"] = 2300] = "DUPLICATE_IDENTIFIER";
    DiagnosticCode[DiagnosticCode["MULTIPLE_PROPS_SAME_NAME"] = 1117] = "MULTIPLE_PROPS_SAME_NAME";
    DiagnosticCode[DiagnosticCode["ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y"] = 2345] = "ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y";
    DiagnosticCode[DiagnosticCode["TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y"] = 2322] = "TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y";
    DiagnosticCode[DiagnosticCode["TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y_DID_YOU_MEAN"] = 2820] = "TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y_DID_YOU_MEAN";
    DiagnosticCode[DiagnosticCode["UNKNOWN_PROP"] = 2353] = "UNKNOWN_PROP";
    DiagnosticCode[DiagnosticCode["MISSING_PROPS"] = 2739] = "MISSING_PROPS";
    DiagnosticCode[DiagnosticCode["MISSING_PROP"] = 2741] = "MISSING_PROP";
    DiagnosticCode[DiagnosticCode["NO_OVERLOAD_MATCHES_CALL"] = 2769] = "NO_OVERLOAD_MATCHES_CALL";
    DiagnosticCode[DiagnosticCode["CANNOT_FIND_NAME"] = 2304] = "CANNOT_FIND_NAME";
    DiagnosticCode[DiagnosticCode["CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y"] = 2552] = "CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y";
    DiagnosticCode[DiagnosticCode["EXPECTED_N_ARGUMENTS"] = 2554] = "EXPECTED_N_ARGUMENTS";
    DiagnosticCode[DiagnosticCode["DEPRECATED_SIGNATURE"] = 6387] = "DEPRECATED_SIGNATURE"; // The signature '..' of '..' is deprecated
})(DiagnosticCode || (exports.DiagnosticCode = DiagnosticCode = {}));
class DiagnosticsProviderImpl {
    constructor(lsAndTsDocResolver, configManager) {
        this.lsAndTsDocResolver = lsAndTsDocResolver;
        this.configManager = configManager;
    }
    async getDiagnostics(document, cancellationToken) {
        const { lang, tsDoc } = await this.getLSAndTSDoc(document);
        if (['coffee', 'coffeescript'].includes(document.getLanguageAttribute('script')) ||
            cancellationToken?.isCancellationRequested) {
            return [];
        }
        // Document preprocessing failed, show parser error instead
        if (tsDoc.parserError) {
            return [
                {
                    range: tsDoc.parserError.range,
                    severity: vscode_languageserver_1.DiagnosticSeverity.Error,
                    source: tsDoc.scriptKind === typescript_1.default.ScriptKind.TSX ||
                        tsDoc.scriptKind === typescript_1.default.ScriptKind.TS
                        ? 'ts'
                        : 'js',
                    message: tsDoc.parserError.message,
                    code: tsDoc.parserError.code
                }
            ];
        }
        let diagnostics = lang.getSyntacticDiagnostics(tsDoc.filePath);
        const checkers = [lang.getSuggestionDiagnostics, lang.getSemanticDiagnostics];
        for (const checker of checkers) {
            if (cancellationToken) {
                // wait a bit so the event loop can check for cancellation
                // or let completion go first
                await new Promise((resolve) => setTimeout(resolve, 10));
                if (cancellationToken.isCancellationRequested) {
                    return [];
                }
            }
            diagnostics.push(...checker.call(lang, tsDoc.filePath));
        }
        return mapAndFilterDiagnostics(diagnostics, document, tsDoc, lang);
    }
    async getDiagnosticsForPullMode(document, previousResultId, cancellationToken) {
        const { tsDoc, lsContainer } = await this.getLSAndTSDoc(document);
        if (cancellationToken?.isCancellationRequested) {
            return {
                kind: 'full',
                items: []
            };
        }
        const resultId = tsDoc.version.toString() + '-' + lsContainer.getProjectVersion();
        if (previousResultId === resultId) {
            return {
                kind: 'unchanged',
                resultId
            };
        }
        const diagnostics = await this.getDiagnostics(document);
        return {
            kind: 'full',
            resultId,
            items: diagnostics
        };
    }
    async getLSAndTSDoc(document) {
        return this.lsAndTsDocResolver.getLSAndTSDoc(document);
    }
}
exports.DiagnosticsProviderImpl = DiagnosticsProviderImpl;
function mapAndFilterDiagnostics(diagnostics, document, tsDoc, lang) {
    const notGenerated = isNotGenerated(tsDoc.getFullText());
    if (lang) {
        const additionalStoreDiagnostics = [];
        for (const diagnostic of diagnostics) {
            if ((diagnostic.code === DiagnosticCode.NO_OVERLOAD_MATCHES_CALL ||
                diagnostic.code === DiagnosticCode.ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y) &&
                !notGenerated(diagnostic)) {
                if ((0, utils_2.isStoreVariableIn$storeDeclaration)(tsDoc.getFullText(), diagnostic.start)) {
                    const storeName = tsDoc
                        .getFullText()
                        .substring(diagnostic.start, diagnostic.start + diagnostic.length);
                    const storeUsages = lang.findReferences(tsDoc.filePath, (0, utils_2.get$storeOffsetOf$storeDeclaration)(tsDoc.getFullText(), diagnostic.start))[0].references;
                    for (const storeUsage of storeUsages) {
                        additionalStoreDiagnostics.push({
                            ...diagnostic,
                            messageText: `Cannot use '${storeName}' as a store. '${storeName}' needs to be an object with a subscribe method on it.\n\n${typescript_1.default.flattenDiagnosticMessageText(diagnostic.messageText, '\n')}`,
                            start: storeUsage.textSpan.start,
                            length: storeUsage.textSpan.length
                        });
                    }
                }
            }
        }
        diagnostics.push(...additionalStoreDiagnostics);
    }
    diagnostics = diagnostics
        .filter(notGenerated)
        .filter((0, utils_3.not)(isUnusedReactiveStatementLabel))
        .filter((diagnostic) => !expectedTransitionThirdArgument(diagnostic, tsDoc, lang));
    if (lang) {
        diagnostics = resolveNoopsInReactiveStatements(lang, diagnostics);
    }
    const source = tsDoc.scriptKind === typescript_1.default.ScriptKind.TSX || tsDoc.scriptKind === typescript_1.default.ScriptKind.TS
        ? 'ts'
        : 'js';
    const mapRange = rangeMapper(tsDoc, document, lang);
    const noFalsePositive = isNoFalsePositive(document, tsDoc);
    const converted = [];
    for (const tsDiag of diagnostics) {
        let diagnostic = {
            range: (0, utils_1.convertRange)(tsDoc, tsDiag),
            severity: (0, utils_1.mapSeverity)(tsDiag.category),
            source,
            message: typescript_1.default.flattenDiagnosticMessageText(tsDiag.messageText, '\n'),
            code: tsDiag.code,
            tags: (0, utils_1.getDiagnosticTag)(tsDiag)
        };
        diagnostic = mapRange(diagnostic);
        moveBindingErrorMessage(tsDiag, tsDoc, diagnostic, document);
        if (!hasNoNegativeLines(diagnostic) || !noFalsePositive(diagnostic)) {
            continue;
        }
        diagnostic = adjustIfNecessary(diagnostic, tsDoc.isSvelte5Plus);
        diagnostic = swapDiagRangeStartEndIfNecessary(diagnostic);
        converted.push(diagnostic);
    }
    return converted;
}
function moveBindingErrorMessage(tsDiag, tsDoc, diagnostic, document) {
    if (tsDiag.code === DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
        tsDiag.start &&
        tsDoc.getText(tsDiag.start, tsDiag.start + tsDiag.length).endsWith('.$$bindings')) {
        let node = tsDoc.svelteNodeAt(diagnostic.range.start);
        while (node && node.type !== 'InlineComponent') {
            node = node.parent;
        }
        if (node) {
            let name = tsDoc.getText(tsDiag.start + tsDiag.length, tsDiag.start + tsDiag.length + 100);
            const quoteIdx = name.indexOf("'");
            name = name.substring(quoteIdx + 1, name.indexOf("'", quoteIdx + 1));
            const binding = node.attributes.find((attr) => attr.type === 'Binding' && attr.name === name);
            if (binding) {
                // try to make the error more readable for english users
                if (diagnostic.message.startsWith("Type '") &&
                    diagnostic.message.includes("is not assignable to type '")) {
                    const idx = diagnostic.message.indexOf(`Type '"`) + `Type '"`.length;
                    const propName = diagnostic.message.substring(idx, diagnostic.message.indexOf('"', idx));
                    diagnostic.message =
                        "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\n" +
                            `To mark a property as bindable: 'let { ${propName} = $bindable() } = $props()'`;
                }
                else {
                    diagnostic.message =
                        "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\n" +
                            `To mark a property as bindable: 'let { prop = $bindable() } = $props()'\n\n` +
                            diagnostic.message;
                }
                diagnostic.range = {
                    start: document.positionAt(binding.start),
                    end: document.positionAt(binding.end)
                };
            }
        }
    }
}
function rangeMapper(snapshot, document, lang) {
    const get$$PropsDefWithCache = (0, utils_3.memoize)(() => lang ? get$$PropsDef(lang, snapshot) : undefined);
    const get$$PropsAliasInfoWithCache = (0, utils_3.memoize)(() => lang ? get$$PropsAliasForInfo(get$$PropsDefWithCache, lang, document) : undefined);
    return (diagnostic) => {
        let range = (0, documents_1.mapRangeToOriginal)(snapshot, diagnostic.range);
        // When lang is unavailable (incremental CLI path), we can't remap negative-line
        // diagnostics. This only affects deprecated $$Props syntax, so it's acceptable.
        if (range.start.line < 0 && lang) {
            range =
                movePropsErrorRangeBackIfNecessary(diagnostic, snapshot, get$$PropsDefWithCache, get$$PropsAliasInfoWithCache) ?? range;
        }
        if (([DiagnosticCode.MISSING_PROP, DiagnosticCode.MISSING_PROPS].includes(diagnostic.code) ||
            (DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
                diagnostic.message.includes("'Properties<"))) &&
            !(0, utils_1.hasNonZeroRange)({ range })) {
            const node = (0, documents_1.getNodeIfIsInStartTag)(document.html, document.offsetAt(range.start));
            if (node) {
                // This is a "some prop missing" error on a component -> remap
                range.start = document.positionAt(node.start + 1);
                range.end = document.positionAt(node.start + 1 + (node.tag?.length || 1));
            }
        }
        return { ...diagnostic, range };
    };
}
function findDiagnosticNode(diagnostic) {
    const { file, start, length } = diagnostic;
    if (!file || !start || !length) {
        return;
    }
    const span = { start, length };
    return (0, utils_2.findNodeAtSpan)(file, span);
}
function copyDiagnosticAndChangeNode(diagnostic) {
    return (node) => ({
        ...diagnostic,
        start: node.getStart(),
        length: node.getWidth()
    });
}
/**
 * In some rare cases mapping of diagnostics does not work and produces negative lines.
 * We filter out these diagnostics with negative lines because else the LSP
 * apparently has a hickup and does not show any diagnostics at all.
 */
function hasNoNegativeLines(diagnostic) {
    return diagnostic.range.start.line >= 0 && diagnostic.range.end.line >= 0;
}
const generatedVarRegex = /'\$\$_\w+(\.\$on)?'/;
function isNoFalsePositive(document, tsDoc) {
    const text = document.getText();
    const usesPug = document.getLanguageAttribute('template') === 'pug';
    return (diagnostic) => {
        if ([DiagnosticCode.MULTIPLE_PROPS_SAME_NAME, DiagnosticCode.DUPLICATE_IDENTIFIER].includes(diagnostic.code)) {
            const node = tsDoc.svelteNodeAt(diagnostic.range.start);
            if ((0, svelte_ast_utils_1.isAttributeName)(node, 'Element') || (0, svelte_ast_utils_1.isEventHandler)(node, 'Element')) {
                return false;
            }
        }
        if (diagnostic.code === DiagnosticCode.DEPRECATED_SIGNATURE &&
            generatedVarRegex.test(diagnostic.message)) {
            // Svelte 5: $on and constructor is deprecated, but we don't want to show this warning for generated code
            return false;
        }
        return (isNoUsedBeforeAssigned(diagnostic, text, tsDoc) &&
            (!usesPug || isNoPugFalsePositive(diagnostic, document)));
    };
}
/**
 * All diagnostics inside the template tag and the unused import/variable diagnostics
 * are marked as false positive.
 */
function isNoPugFalsePositive(diagnostic, document) {
    return (!(0, documents_1.isRangeInTag)(diagnostic.range, document.templateInfo) &&
        diagnostic.code !== DiagnosticCode.NEVER_READ &&
        diagnostic.code !== DiagnosticCode.ALL_IMPORTS_UNUSED);
}
/**
 * Variable used before being assigned, can happen when  you do `export let x`
 * without assigning a value in strict mode. Should not throw an error here
 * but on the component-user-side ("you did not set a required prop").
 */
function isNoUsedBeforeAssigned(diagnostic, text, tsDoc) {
    if (diagnostic.code !== DiagnosticCode.USED_BEFORE_ASSIGNED) {
        return true;
    }
    return !tsDoc.hasProp((0, documents_1.getTextInRange)(diagnostic.range, text));
}
/**
 * Some diagnostics have JSX-specific or confusing nomenclature. Enhance/adjust them for more clarity.
 */
function adjustIfNecessary(diagnostic, isSvelte5Plus) {
    if (diagnostic.code === DiagnosticCode.ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
        diagnostic.message.includes('ConstructorOfATypedSvelteComponent')) {
        return {
            ...diagnostic,
            message: diagnostic.message +
                '\n\nPossible causes:\n' +
                '- You use the instance type of a component where you should use the constructor type\n' +
                '- Type definitions are missing for this Svelte Component. ' +
                (isSvelte5Plus
                    ? ''
                    : 'If you are using Svelte 3.31+, use SvelteComponentTyped to add a definition:\n' +
                        '  import type { SvelteComponentTyped } from "svelte";\n' +
                        '  class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}')
        };
    }
    if (diagnostic.code === DiagnosticCode.MODIFIERS_CANNOT_APPEAR_HERE) {
        return {
            ...diagnostic,
            message: diagnostic.message +
                '\nIf this is a declare statement, move it into <script context="module">..</script>'
        };
    }
    return diagnostic;
}
/**
 * Due to source mapping, some ranges may be swapped: Start is end. Swap back in this case.
 */
function swapDiagRangeStartEndIfNecessary(diag) {
    diag.range = (0, utils_3.swapRangeStartEndIfNecessary)(diag.range);
    return diag;
}
/**
 * Checks if diagnostic is not within a section that should be completely ignored
 * because it's purely generated.
 */
function isNotGenerated(text) {
    return (diagnostic) => {
        if (diagnostic.start === undefined || diagnostic.length === undefined) {
            return true;
        }
        return !(0, utils_2.isInGeneratedCode)(text, diagnostic.start, diagnostic.start + diagnostic.length);
    };
}
function isUnusedReactiveStatementLabel(diagnostic) {
    if (diagnostic.code !== DiagnosticCode.UNUSED_LABEL) {
        return false;
    }
    const diagNode = findDiagnosticNode(diagnostic);
    if (!diagNode) {
        return false;
    }
    // TS warning targets the identifier
    if (!typescript_1.default.isIdentifier(diagNode)) {
        return false;
    }
    if (!diagNode.parent) {
        return false;
    }
    return (0, utils_2.isReactiveStatement)(diagNode.parent);
}
/**
 * Checks if diagnostics should be ignored because they report an unused expression* in
 * a reactive statement, and those actually have side effects in Svelte (hinting deps).
 *
 *     $: x, update()
 *
 * Only `let` (i.e. reactive) variables are ignored. For the others, new diagnostics are
 * emitted, centered on the (non reactive) identifiers in the initial warning.
 */
function resolveNoopsInReactiveStatements(lang, diagnostics) {
    const isLet = (file) => (node) => {
        const defs = lang.getDefinitionAtPosition(file.fileName, node.getStart());
        return !!defs && defs.some((def) => def.fileName === file.fileName && def.kind === 'let');
    };
    const expandRemainingNoopWarnings = (diagnostic) => {
        const { code, file } = diagnostic;
        // guard: missing info
        if (!file) {
            return;
        }
        // guard: not target error
        const isNoopDiag = code === DiagnosticCode.NOOP_IN_COMMAS;
        if (!isNoopDiag) {
            return;
        }
        const diagNode = findDiagnosticNode(diagnostic);
        if (!diagNode) {
            return;
        }
        if (!(0, utils_2.isInReactiveStatement)(diagNode)) {
            return;
        }
        return (
        // for all identifiers in diagnostic node
        (0, utils_2.gatherIdentifiers)(diagNode)
            // ignore `let` (i.e. reactive) variables
            .filter((0, utils_3.not)(isLet(file)))
            // and create targeted diagnostics just for the remaining ids
            .map(copyDiagnosticAndChangeNode(diagnostic)));
    };
    const expandedDiagnostics = (0, utils_3.passMap)(diagnostics, expandRemainingNoopWarnings).flat();
    return expandedDiagnostics.length === diagnostics.length
        ? expandedDiagnostics
        : // This can generate duplicate diagnostics
            expandedDiagnostics.filter(dedupDiagnostics());
}
function dedupDiagnostics() {
    const hashDiagnostic = (diag) => [diag.start, diag.length, diag.category, diag.source, diag.code]
        .map((x) => JSON.stringify(x))
        .join(':');
    const known = new Set();
    return (diag) => {
        const key = hashDiagnostic(diag);
        if (known.has(key)) {
            return false;
        }
        else {
            known.add(key);
            return true;
        }
    };
}
function get$$PropsAliasForInfo(get$$PropsDefWithCache, lang, document) {
    if (!/type\s+\$\$Props[\s\n]+=/.test(document.getText())) {
        return;
    }
    const propsDef = get$$PropsDefWithCache();
    if (!propsDef || !typescript_1.default.isTypeAliasDeclaration(propsDef)) {
        return;
    }
    const type = lang.getProgram()?.getTypeChecker()?.getTypeAtLocation(propsDef.name);
    if (!type) {
        return;
    }
    // TS says symbol is always defined but it's not
    const rootSymbolName = (type.aliasSymbol ?? type.symbol)?.name;
    if (!rootSymbolName) {
        return;
    }
    return [rootSymbolName, propsDef];
}
function get$$PropsDef(lang, snapshot) {
    const program = lang.getProgram();
    const sourceFile = program?.getSourceFile(snapshot.filePath);
    if (!program || !sourceFile) {
        return undefined;
    }
    const renderFunction = sourceFile.statements.find((statement) => typescript_1.default.isFunctionDeclaration(statement) &&
        statement.name?.getText() === svelte2tsx_1.internalHelpers.renderName);
    return renderFunction?.body?.statements.find((node) => (typescript_1.default.isTypeAliasDeclaration(node) || typescript_1.default.isInterfaceDeclaration(node)) &&
        node.name.getText() === '$$Props');
}
function movePropsErrorRangeBackIfNecessary(diagnostic, snapshot, get$$PropsDefWithCache, get$$PropsAliasForWithCache) {
    const possibly$$PropsError = (0, utils_2.isAfterSvelte2TsxPropsReturn)(snapshot.getFullText(), snapshot.offsetAt(diagnostic.range.start));
    if (!possibly$$PropsError) {
        return;
    }
    if (diagnostic.message.includes('$$Props')) {
        const propsDef = get$$PropsDefWithCache();
        const generatedPropsStart = propsDef?.name.getStart();
        const propsStart = generatedPropsStart != null &&
            snapshot.getOriginalPosition(snapshot.positionAt(generatedPropsStart));
        if (propsStart) {
            return {
                start: propsStart,
                end: { ...propsStart, character: propsStart.character + '$$Props'.length }
            };
        }
        return;
    }
    const aliasForInfo = get$$PropsAliasForWithCache();
    if (!aliasForInfo) {
        return;
    }
    const [aliasFor, propsDef] = aliasForInfo;
    if (diagnostic.message.includes(aliasFor)) {
        return (0, documents_1.mapRangeToOriginal)(snapshot, {
            start: snapshot.positionAt(propsDef.name.getStart()),
            end: snapshot.positionAt(propsDef.name.getEnd())
        });
    }
}
function expectedTransitionThirdArgument(diagnostic, tsDoc, lang) {
    if (diagnostic.code !== DiagnosticCode.EXPECTED_N_ARGUMENTS ||
        !diagnostic.start ||
        !tsDoc.getText(0, diagnostic.start).endsWith('__sveltets_2_ensureTransition(')) {
        return false;
    }
    const node = findDiagnosticNode(diagnostic);
    if (!node) {
        return false;
    }
    // in TypeScript 5.4 the error is on the function name
    // in earlier versions it's on the whole call expression
    const callExpression = typescript_1.default.isIdentifier(node) && typescript_1.default.isCallExpression(node.parent)
        ? node.parent
        : (0, utils_2.findNodeAtSpan)(node, { start: node.getStart(), length: node.getWidth() }, typescript_1.default.isCallExpression);
    if (!lang) {
        // Without a language service we can't resolve the signature to check parameter count.
        // Fall back to checking the message text for " 3" (i.e. "Expected 3 arguments").
        // This is only for the __sveltets_2_ensureTransition wrapper and unlikely to false-positive.
        return (0, typescript_1.flattenDiagnosticMessageText)(diagnostic.messageText, '\n').includes(' 3');
    }
    const signature = callExpression && lang.getProgram()?.getTypeChecker().getResolvedSignature(callExpression);
    return (signature?.parameters.filter((parameter) => !(parameter.flags & typescript_1.default.SymbolFlags.Optional))
        .length === 3);
}
//# sourceMappingURL=DiagnosticsProvider.js.map