"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;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const assert = __importStar(require("assert"));
const plugins_1 = require("../../../src/plugins");
const documents_1 = require("../../../src/lib/documents");
const vscode_languageserver_1 = require("vscode-languageserver");
const ls_config_1 = require("../../../src/ls-config");
const importPackage = __importStar(require("../../../src/importPackage"));
const sinon_1 = __importDefault(require("sinon"));
const path_1 = require("path");
const utils_1 = require("../../../src/utils");
const compiler_1 = require("svelte/compiler");
const isSvelte5Plus = Number(compiler_1.VERSION.split('.')[0]) >= 5;
describe('Svelte Plugin', () => {
    function setup(content, prettierConfig, { trusted = true, documentUri = 'file:///hello.svelte' } = {}) {
        const document = new documents_1.Document(documentUri, content);
        const docManager = new documents_1.DocumentManager(() => document);
        const pluginManager = new ls_config_1.LSConfigManager();
        pluginManager.updateIsTrusted(trusted);
        pluginManager.updatePrettierConfig(prettierConfig);
        const plugin = new plugins_1.SveltePlugin(pluginManager);
        docManager.openClientDocument('some doc');
        return { plugin, document };
    }
    it('provides diagnostic warnings', async () => {
        const { plugin, document } = setup('<h1>Hello, world!</h1>\n<img src="hello.png">');
        const diagnostics = await plugin.getDiagnostics(document);
        const diagnostic = vscode_languageserver_1.Diagnostic.create(vscode_languageserver_1.Range.create(1, 0, 1, 21), isSvelte5Plus
            ? '`<img>` element should have an alt attribute\nhttps://svelte.dev/e/a11y_missing_attribute'
            : 'A11y: <img> element should have an alt attribute', vscode_languageserver_1.DiagnosticSeverity.Warning, isSvelte5Plus ? 'a11y_missing_attribute' : 'a11y-missing-attribute', 'svelte');
        diagnostic.codeDescription = {
            href: 'https://svelte.dev/docs/svelte/compiler-warnings#a11y_missing_attribute'
        };
        assert.deepStrictEqual(diagnostics, [diagnostic]);
    });
    it('provides diagnostic errors', async () => {
        const { plugin, document } = setup('<div bind:whatever></div>');
        const diagnostics = await plugin.getDiagnostics(document);
        const diagnostic = vscode_languageserver_1.Diagnostic.create(vscode_languageserver_1.Range.create(0, isSvelte5Plus ? 5 : 10, 0, 18), isSvelte5Plus
            ? '`bind:whatever` is not a valid binding\nhttps://svelte.dev/e/bind_invalid_name'
            : 'whatever is not declared', vscode_languageserver_1.DiagnosticSeverity.Error, isSvelte5Plus ? 'bind_invalid_name' : 'binding-undeclared', 'svelte');
        diagnostic.codeDescription = {
            href: isSvelte5Plus
                ? 'https://svelte.dev/docs/svelte/compiler-errors#bind_invalid_name'
                : // doesn't actually exist but at least points to the page
                    'https://svelte.dev/docs/svelte/compiler-errors#binding_undeclared'
        };
        assert.deepStrictEqual(diagnostics, [diagnostic]);
    });
    it('provides no diagnostic errors when untrusted', async () => {
        const { plugin, document } = setup('<div bind:whatever></div>', {}, { trusted: false });
        const diagnostics = await plugin.getDiagnostics(document);
        assert.deepStrictEqual(diagnostics, []);
    });
    describe('#formatDocument', () => {
        const defaultDocumentPath = '/hello.svelte';
        function stubPrettierV2(config) {
            const formatStub = sinon_1.default.stub().returns('formatted');
            sinon_1.default.stub(importPackage, 'importPrettier').returns({
                version: '2.8.0',
                resolveConfig: () => Promise.resolve(config),
                getFileInfo: () => ({ ignored: false }),
                format: formatStub,
                getSupportInfo: () => ({ languages: [{ name: 'svelte' }] })
            });
            return formatStub;
        }
        async function testFormat(config, fallbackPrettierConfig, options, stubPrettier = stubPrettierV2) {
            const { plugin, document } = setup('unformatted', fallbackPrettierConfig, options);
            const formatStub = stubPrettier(config);
            const formatted = await plugin.formatDocument(document, {
                insertSpaces: true,
                tabSize: 4
            });
            assert.deepStrictEqual(formatted, [
                {
                    newText: 'formatted',
                    range: {
                        end: {
                            character: 11,
                            line: 0
                        },
                        start: {
                            character: 0,
                            line: 0
                        }
                    }
                }
            ]);
            return formatStub;
        }
        afterEach(() => {
            sinon_1.default.restore();
        });
        it('should use config for formatting', async () => {
            const formatStub = await testFormat({ fromConfig: true }, { fallbackConfig: true });
            sinon_1.default.assert.calledOnceWithExactly(formatStub, 'unformatted', {
                fromConfig: true,
                plugins: [],
                parser: 'svelte',
                filepath: defaultDocumentPath
            });
        });
        it('can resolve plugin for formatting', async () => {
            const documentUri = (0, utils_1.pathToUrl)((0, path_1.join)(__dirname, 'testFiles', 'do-not-exist.svelte'));
            const formatStub = await testFormat({ fromConfig: true, plugins: ['prettier-plugin-svelte'] }, { fallbackConfig: true }, { documentUri });
            sinon_1.default.assert.calledOnceWithExactly(formatStub, 'unformatted', {
                fromConfig: true,
                plugins: [
                    require.resolve('prettier-plugin-svelte', { paths: [(0, utils_1.urlToPath)(documentUri)] })
                ],
                parser: 'svelte',
                filepath: (0, utils_1.urlToPath)(documentUri)
            });
        });
        const defaultSettings = {
            svelteSortOrder: 'options-scripts-markup-styles',
            svelteStrictMode: false,
            svelteAllowShorthand: true,
            svelteBracketNewLine: true,
            svelteIndentScriptAndStyle: true,
            printWidth: 80,
            singleQuote: false
        };
        it('should use prettier fallback config for formatting', async () => {
            const formatStub = await testFormat(undefined, { fallbackConfig: true });
            sinon_1.default.assert.calledOnceWithExactly(formatStub, 'unformatted', {
                fallbackConfig: true,
                plugins: [],
                parser: 'svelte',
                filepath: defaultDocumentPath,
                ...defaultSettings
            });
        });
        it('should use FormattingOptions for formatting', async () => {
            const formatStub = await testFormat(undefined, undefined);
            sinon_1.default.assert.calledOnceWithExactly(formatStub, 'unformatted', {
                tabWidth: 4,
                useTabs: false,
                plugins: [],
                parser: 'svelte',
                filepath: defaultDocumentPath,
                ...defaultSettings
            });
        });
        it('should use FormattingOptions for formatting when configs are empty objects', async () => {
            const formatStub = await testFormat({}, {});
            sinon_1.default.assert.calledOnceWithExactly(formatStub, 'unformatted', {
                tabWidth: 4,
                useTabs: false,
                plugins: [],
                parser: 'svelte',
                filepath: defaultDocumentPath,
                ...defaultSettings
            });
        });
        it('should load the user prettier version (version 2)', async () => {
            function stubPrettier(config) {
                const formatStub = sinon_1.default.stub().returns('formatted');
                sinon_1.default
                    .stub(importPackage, 'importPrettier')
                    .onFirstCall()
                    .returns({
                    version: '2.8.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: formatStub,
                    getSupportInfo: () => ({ languages: [{ name: 'svelte' }] })
                })
                    .onSecondCall()
                    .throws(new Error('should not be called'));
                return formatStub;
            }
            await testFormat({}, {}, undefined, stubPrettier);
        });
        it("should load user plugin if it's module", async () => {
            function stubPrettier(config) {
                const formatStub = sinon_1.default.stub().returns('formatted');
                sinon_1.default
                    .stub(importPackage, 'importPrettier')
                    .onFirstCall()
                    .returns({
                    version: '2.8.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: formatStub,
                    getSupportInfo: () => ({ languages: [{ name: 'svelte' }] })
                })
                    .onSecondCall()
                    .throws(new Error('should not be called'));
                return formatStub;
            }
            await testFormat({}, {
                plugins: [require('prettier-plugin-svelte')]
            }, undefined, stubPrettier);
        });
        it('should load the user prettier version (version 2)', async () => {
            function stubPrettier(config) {
                const formatStub = sinon_1.default.stub().returns(Promise.resolve('formatted'));
                sinon_1.default
                    .stub(importPackage, 'importPrettier')
                    .onFirstCall()
                    .returns({
                    version: '2.0.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: formatStub,
                    getSupportInfo: () => Promise.resolve({ languages: [] })
                })
                    .onSecondCall()
                    .throws(new Error('should not be called'));
                return formatStub;
            }
            await testFormat(
            // written like this to not trigger require.resolve which fails here
            { plugins: ['./node_modules/prettier-plugin-svelte'] }, {}, undefined, stubPrettier);
        });
        it('should fall back to built-in prettier version', async () => {
            function stubPrettier(config) {
                const formatStub = sinon_1.default.stub().returns('formatted');
                sinon_1.default
                    .stub(importPackage, 'importPrettier')
                    .onFirstCall()
                    .returns({
                    version: '2.8.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: () => {
                        throw new Error('should not be called');
                    },
                    getSupportInfo: () => Promise.resolve({ languages: [] })
                })
                    .onSecondCall()
                    .returns({
                    version: '3.1.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: formatStub,
                    getSupportInfo: () => ({ languages: [] })
                })
                    .onThirdCall()
                    .throws(new Error('should not be called'));
                return formatStub;
            }
            await testFormat({}, {}, undefined, stubPrettier);
        });
        it('should fall back to built-in prettier version when failing to resolve plugins config', async () => {
            function stubPrettier(config) {
                const formatStub = sinon_1.default.stub().returns('formatted');
                sinon_1.default
                    .stub(importPackage, 'importPrettier')
                    .onFirstCall()
                    .returns({
                    version: '2.8.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: () => {
                        throw new Error('should not be called');
                    },
                    getSupportInfo: () => Promise.resolve({ languages: [] })
                })
                    .onSecondCall()
                    .returns({
                    version: '3.0.0',
                    resolveConfig: () => Promise.resolve(config),
                    getFileInfo: () => ({ ignored: false }),
                    format: formatStub,
                    getSupportInfo: () => ({ languages: [] })
                })
                    .onThirdCall()
                    .throws(new Error('should not be called'));
                return formatStub;
            }
            await testFormat({
                plugins: ['@do-not-exist/prettier-plugin-svelte']
            }, {}, undefined, stubPrettier);
        });
    });
    it('can cancel completion before promise resolved', async () => {
        const { plugin, document } = setup('{#');
        const cancellationTokenSource = new vscode_languageserver_1.CancellationTokenSource();
        const completionsPromise = plugin.getCompletions(document, { line: 0, character: 2 }, undefined, cancellationTokenSource.token);
        cancellationTokenSource.cancel();
        assert.deepStrictEqual(await completionsPromise, null);
    });
    it('can cancel code action before promise resolved', async () => {
        const { plugin, document } = setup('<a></a>');
        const cancellationTokenSource = new vscode_languageserver_1.CancellationTokenSource();
        const range = {
            start: { line: 0, character: 0 },
            end: { line: 0, character: 7 }
        };
        const codeActionPromise = plugin.getCodeActions(document, range, {
            diagnostics: [
                {
                    message: 'A11y: <a> element should have child content',
                    code: 'a11y-missing-content',
                    range,
                    severity: vscode_languageserver_1.DiagnosticSeverity.Warning,
                    source: 'svelte'
                }
            ]
        }, cancellationTokenSource.token);
        cancellationTokenSource.cancel();
        assert.deepStrictEqual(await codeActionPromise, []);
    });
});
//# sourceMappingURL=SveltePlugin.test.js.map