"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const sinon_1 = __importDefault(require("sinon"));
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
const documents_1 = require("../../src/lib/documents");
const plugins_1 = require("../../src/plugins");
const vscode_languageserver_1 = require("vscode-languageserver");
const assert_1 = __importDefault(require("assert"));
describe('PluginHost', () => {
    const textDocument = {
        uri: 'file:///hello.svelte',
        version: 0,
        languageId: 'svelte',
        text: 'Hello, world!'
    };
    function setup(pluginProviderStubs, config = {
        definitionLinkSupport: true,
        filterIncompleteCompletions: false
    }) {
        const docManager = new documents_1.DocumentManager((textDocument) => new documents_1.Document(textDocument.uri, textDocument.text));
        const pluginHost = new plugins_1.PluginHost(docManager);
        const plugin = {
            ...pluginProviderStubs,
            __name: 'test'
        };
        pluginHost.initialize(config);
        pluginHost.register(plugin);
        return { docManager, pluginHost, plugin };
    }
    it('executes getDiagnostics on plugins', async () => {
        const { docManager, pluginHost, plugin } = setup({
            getDiagnostics: sinon_1.default.stub().returns([])
        });
        const document = docManager.openClientDocument(textDocument);
        await pluginHost.getDiagnostics(textDocument);
        sinon_1.default.assert.calledOnce(plugin.getDiagnostics);
        sinon_1.default.assert.calledWithExactly(plugin.getDiagnostics, document, undefined);
    });
    it('executes doHover on plugins', async () => {
        const { docManager, pluginHost, plugin } = setup({
            doHover: sinon_1.default.stub().returns(null)
        });
        const document = docManager.openClientDocument(textDocument);
        const pos = vscode_languageserver_types_1.Position.create(0, 0);
        await pluginHost.doHover(textDocument, pos);
        sinon_1.default.assert.calledOnce(plugin.doHover);
        sinon_1.default.assert.calledWithExactly(plugin.doHover, document, pos);
    });
    it('executes getCompletions on plugins', async () => {
        const { docManager, pluginHost, plugin } = setup({
            getCompletions: sinon_1.default.stub().returns({ items: [] })
        });
        const document = docManager.openClientDocument(textDocument);
        const pos = vscode_languageserver_types_1.Position.create(0, 0);
        await pluginHost.getCompletions(textDocument, pos, {
            triggerKind: vscode_languageserver_1.CompletionTriggerKind.TriggerCharacter,
            triggerCharacter: '.'
        });
        sinon_1.default.assert.calledOnce(plugin.getCompletions);
        sinon_1.default.assert.calledWithExactly(plugin.getCompletions, document, pos, {
            triggerKind: vscode_languageserver_1.CompletionTriggerKind.TriggerCharacter,
            triggerCharacter: '.'
        }, undefined);
    });
    describe('pull mode diagnostics', () => {
        it('merge pull diagnostics results', async () => {
            const { docManager, pluginHost } = setup({
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'full',
                        items: [],
                        resultId: '1'
                    };
                }
            });
            const plugin2 = {
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'full',
                        items: [],
                        resultId: '2'
                    };
                },
                __name: 'test2'
            };
            pluginHost.register(plugin2);
            docManager.openClientDocument(textDocument);
            const diagnostics = await pluginHost.getDiagnosticsForPullMode(textDocument, undefined);
            assert_1.default.deepStrictEqual(diagnostics, {
                kind: 'full',
                items: [],
                resultId: JSON.stringify({ test: '1', test2: '2' })
            });
        });
        it('merge pull diagnostics unchanged results', async () => {
            const { docManager, pluginHost } = setup({
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'unchanged',
                        resultId: '1'
                    };
                }
            });
            const plugin2 = {
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'unchanged',
                        resultId: '2'
                    };
                },
                __name: 'test2'
            };
            pluginHost.register(plugin2);
            docManager.openClientDocument(textDocument);
            const diagnostics = await pluginHost.getDiagnosticsForPullMode(textDocument, undefined);
            assert_1.default.deepStrictEqual(diagnostics, {
                kind: 'unchanged',
                resultId: JSON.stringify({ test: '1', test2: '2' })
            });
        });
        it('merge pull diagnostics when some results are unchanged', async () => {
            const { docManager, pluginHost } = setup({
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'unchanged',
                        resultId: '1'
                    };
                }
            });
            const plugin2 = {
                getDiagnostics() {
                    return [];
                },
                getDiagnosticsForPullMode() {
                    return {
                        kind: 'full',
                        items: [],
                        resultId: '2'
                    };
                },
                __name: 'test2'
            };
            pluginHost.register(plugin2);
            docManager.openClientDocument(textDocument);
            const diagnostics = await pluginHost.getDiagnosticsForPullMode(textDocument, undefined);
            assert_1.default.deepStrictEqual(diagnostics, {
                kind: 'full',
                items: [],
                resultId: JSON.stringify({ test: '1', test2: '2' })
            });
        });
    });
    describe('getCompletions (incomplete)', () => {
        function setupGetIncompleteCompletions(filterServerSide) {
            const { docManager, pluginHost } = setup({
                getCompletions: sinon_1.default.stub().returns({
                    isIncomplete: true,
                    items: [{ label: 'Hello' }, { label: 'foo' }]
                })
            }, { definitionLinkSupport: true, filterIncompleteCompletions: filterServerSide });
            docManager.openClientDocument(textDocument);
            return pluginHost;
        }
        it('filters client side', async () => {
            const pluginHost = setupGetIncompleteCompletions(false);
            const completions = await pluginHost.getCompletions(textDocument, vscode_languageserver_types_1.Position.create(0, 2));
            assert_1.default.deepStrictEqual(completions.items, [
                { label: 'Hello' },
                { label: 'foo' }
            ]);
        });
        it('filters server side', async () => {
            const pluginHost = setupGetIncompleteCompletions(true);
            const completions = await pluginHost.getCompletions(textDocument, vscode_languageserver_types_1.Position.create(0, 2));
            assert_1.default.deepStrictEqual(completions.items, [{ label: 'Hello' }]);
        });
    });
    describe('getDefinitions', () => {
        function setupGetDefinitions(linkSupport) {
            const { pluginHost, docManager } = setup({
                getDefinitions: sinon_1.default.stub().returns([
                    {
                        targetRange: vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(0, 2)),
                        targetSelectionRange: vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(0, 1)),
                        targetUri: 'uri'
                    }
                ])
            }, { definitionLinkSupport: linkSupport, filterIncompleteCompletions: false });
            docManager.openClientDocument(textDocument);
            return pluginHost;
        }
        it('uses LocationLink', async () => {
            const pluginHost = setupGetDefinitions(true);
            const definitions = await pluginHost.getDefinitions(textDocument, vscode_languageserver_types_1.Position.create(0, 0));
            assert_1.default.deepStrictEqual(definitions, [
                {
                    targetRange: vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(0, 2)),
                    targetSelectionRange: vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(0, 1)),
                    targetUri: 'uri'
                }
            ]);
        });
        it('uses Location', async () => {
            const pluginHost = setupGetDefinitions(false);
            const definitions = await pluginHost.getDefinitions(textDocument, vscode_languageserver_types_1.Position.create(0, 0));
            assert_1.default.deepStrictEqual(definitions, [
                {
                    range: vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(0, 1)),
                    uri: 'uri'
                }
            ]);
        });
    });
    describe('getHierarchicalDocumentSymbols', () => {
        it('converts flat symbols to hierarchical structure', async () => {
            const cancellation_token = {
                isCancellationRequested: false,
                onCancellationRequested: () => ({ dispose: () => { } })
            };
            const flat_symbols = [
                // Root level class (lines 0-10)
                vscode_languageserver_types_1.SymbolInformation.create('MyClass', vscode_languageserver_types_1.SymbolKind.Class, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(10, 0)), 'file:///hello.svelte'),
                // Method inside class (lines 1-5)
                vscode_languageserver_types_1.SymbolInformation.create('myMethod', vscode_languageserver_types_1.SymbolKind.Method, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(1, 0), vscode_languageserver_types_1.Position.create(5, 0)), 'file:///hello.svelte'),
                // Variable inside method (lines 2-3)
                vscode_languageserver_types_1.SymbolInformation.create('localVar', vscode_languageserver_types_1.SymbolKind.Variable, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(2, 0), vscode_languageserver_types_1.Position.create(3, 0)), 'file:///hello.svelte'),
                // Another method in class (lines 6-8)
                vscode_languageserver_types_1.SymbolInformation.create('anotherMethod', vscode_languageserver_types_1.SymbolKind.Method, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(6, 0), vscode_languageserver_types_1.Position.create(8, 0)), 'file:///hello.svelte'),
                // Root level function (lines 12-15)
                vscode_languageserver_types_1.SymbolInformation.create('topLevelFunction', vscode_languageserver_types_1.SymbolKind.Function, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(12, 0), vscode_languageserver_types_1.Position.create(15, 0)), 'file:///hello.svelte')
            ];
            const { docManager, pluginHost } = setup({});
            sinon_1.default.stub(pluginHost, 'getDocumentSymbols').returns(Promise.resolve(flat_symbols));
            docManager.openClientDocument(textDocument);
            const result = await pluginHost.getHierarchicalDocumentSymbols(textDocument, cancellation_token);
            // Should have 2 root symbols: MyClass and topLevelFunction
            assert_1.default.strictEqual(result.length, 2);
            // Check first root symbol (MyClass)
            assert_1.default.strictEqual(result[0].name, 'MyClass');
            assert_1.default.strictEqual(result[0].kind, vscode_languageserver_types_1.SymbolKind.Class);
            assert_1.default.strictEqual(result[0].children?.length, 2);
            // Check children of MyClass
            assert_1.default.strictEqual(result[0].children[0].name, 'myMethod');
            assert_1.default.strictEqual(result[0].children[0].kind, vscode_languageserver_types_1.SymbolKind.Method);
            assert_1.default.strictEqual(result[0].children[0].children?.length, 1);
            // Check nested child (localVar inside myMethod)
            assert_1.default.strictEqual(result[0].children[0].children[0].name, 'localVar');
            assert_1.default.strictEqual(result[0].children[0].children[0].kind, vscode_languageserver_types_1.SymbolKind.Variable);
            assert_1.default.strictEqual(result[0].children[0].children[0].children?.length, 0);
            // Check second child of MyClass
            assert_1.default.strictEqual(result[0].children[1].name, 'anotherMethod');
            assert_1.default.strictEqual(result[0].children[1].kind, vscode_languageserver_types_1.SymbolKind.Method);
            assert_1.default.strictEqual(result[0].children[1].children?.length, 0);
            // Check second root symbol (topLevelFunction)
            assert_1.default.strictEqual(result[1].name, 'topLevelFunction');
            assert_1.default.strictEqual(result[1].kind, vscode_languageserver_types_1.SymbolKind.Function);
            assert_1.default.strictEqual(result[1].children?.length, 0);
        });
        it('handles empty symbol list', async () => {
            const cancellation_token = {
                isCancellationRequested: false,
                onCancellationRequested: () => ({ dispose: () => { } })
            };
            const { docManager, pluginHost } = setup({});
            sinon_1.default.stub(pluginHost, 'getDocumentSymbols').returns(Promise.resolve([]));
            docManager.openClientDocument(textDocument);
            const result = await pluginHost.getHierarchicalDocumentSymbols(textDocument, cancellation_token);
            assert_1.default.deepStrictEqual(result, []);
        });
        it('handles symbols with same start position', async () => {
            const cancellation_token = {
                isCancellationRequested: false,
                onCancellationRequested: () => ({ dispose: () => { } })
            };
            const flat_symbols = [
                // Two symbols starting at same position, longer one should be parent
                vscode_languageserver_types_1.SymbolInformation.create('outer', vscode_languageserver_types_1.SymbolKind.Class, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(10, 0)), 'file:///hello.svelte'),
                vscode_languageserver_types_1.SymbolInformation.create('inner', vscode_languageserver_types_1.SymbolKind.Method, vscode_languageserver_types_1.Range.create(vscode_languageserver_types_1.Position.create(0, 0), vscode_languageserver_types_1.Position.create(5, 0)), 'file:///hello.svelte')
            ];
            const { docManager, pluginHost } = setup({});
            sinon_1.default.stub(pluginHost, 'getDocumentSymbols').returns(Promise.resolve(flat_symbols));
            docManager.openClientDocument(textDocument);
            const result = await pluginHost.getHierarchicalDocumentSymbols(textDocument, cancellation_token);
            assert_1.default.strictEqual(result.length, 1);
            assert_1.default.strictEqual(result[0].name, 'outer');
            assert_1.default.strictEqual(result[0].children?.length, 1);
            assert_1.default.strictEqual(result[0].children[0].name, 'inner');
        });
    });
});
//# sourceMappingURL=PluginHost.test.js.map