"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
const assert = require("assert");
const lsp = require("vscode-languageserver-types");
const documentLinks_1 = require("../../languageFeatures/documentLinks");
const extractLinkDef_1 = require("../../languageFeatures/codeActions/extractLinkDef");
const tableOfContents_1 = require("../../tableOfContents");
const cancellation_1 = require("../../util/cancellation");
const engine_1 = require("../engine");
const inMemoryDocument_1 = require("../inMemoryDocument");
const inMemoryWorkspace_1 = require("../inMemoryWorkspace");
const nulLogging_1 = require("../nulLogging");
const util_1 = require("../util");
const range_1 = require("../../types/range");
const config_1 = require("../../config");
async function getActions(store, doc, pos) {
    const workspace = store.add(new inMemoryWorkspace_1.InMemoryWorkspace([doc]));
    const engine = (0, engine_1.createNewMarkdownEngine)();
    const config = (0, config_1.getLsConfiguration)({});
    const tocProvider = store.add(new tableOfContents_1.MdTableOfContentsProvider(engine, workspace, nulLogging_1.nulLogger));
    const linkProvider = store.add(new documentLinks_1.MdLinkProvider(config, engine, workspace, tocProvider, nulLogging_1.nulLogger));
    const provider = new extractLinkDef_1.MdExtractLinkDefinitionCodeActionProvider(linkProvider);
    return provider.getActions(doc, (0, range_1.makeRange)(pos, pos), lsp.CodeActionContext.create([], undefined, undefined), cancellation_1.noopToken);
}
function assertActiveActionCount(actions, expectedCount) {
    assert.strictEqual(actions.filter(action => !action.disabled).length, expectedCount);
}
suite('Extract link definition code action', () => {
    test('Should return disabled code action when not on link', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`test`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assert.strictEqual(actions.length, 1);
        assert.strictEqual(actions[0].disabled?.reason, extractLinkDef_1.MdExtractLinkDefinitionCodeActionProvider.notOnLinkAction.disabled.reason);
    }));
    test('Should return disabled code action when already on reference link', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text][ref]`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assert.strictEqual(actions.length, 1);
        assert.strictEqual(actions[0].disabled?.reason, extractLinkDef_1.MdExtractLinkDefinitionCodeActionProvider.alreadyRefLinkAction.disabled.reason);
    }));
    test('Should return action for simple internal link', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](./img.png)`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assert.strictEqual(actions.length, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[def]: ./img.png`));
    }));
    test('Should be triggerable on link text or title', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`a [text](./img.png) b`));
        const expectedNewContent = (0, util_1.joinLines)(`a [text][def] b`, ``, `[def]: ./img.png`);
        {
            // Before link
            const actions = await getActions(store, doc, { line: 0, character: 1 });
            assert.strictEqual(actions.length, 1);
            assert.strictEqual(actions[0].disabled?.reason, extractLinkDef_1.MdExtractLinkDefinitionCodeActionProvider.notOnLinkAction.disabled?.reason);
        }
        {
            // On opening `[`
            const actions = await getActions(store, doc, { line: 0, character: 2 });
            assertActiveActionCount(actions, 1);
            assert.strictEqual((0, util_1.applyActionEdit)(doc, actions[0]), expectedNewContent);
        }
        {
            // On opening link text
            const actions = await getActions(store, doc, { line: 0, character: 5 });
            assertActiveActionCount(actions, 1);
            assert.strictEqual((0, util_1.applyActionEdit)(doc, actions[0]), expectedNewContent);
        }
        {
            // On link target
            const actions = await getActions(store, doc, { line: 0, character: 14 });
            assertActiveActionCount(actions, 1);
            assert.strictEqual((0, util_1.applyActionEdit)(doc, actions[0]), expectedNewContent);
        }
        {
            // On closing `)`
            const actions = await getActions(store, doc, { line: 0, character: 19 });
            assertActiveActionCount(actions, 1);
            assert.strictEqual((0, util_1.applyActionEdit)(doc, actions[0]), expectedNewContent);
        }
        {
            // After link
            const actions = await getActions(store, doc, { line: 0, character: 20 });
            assert.strictEqual(actions.length, 1);
            assert.strictEqual(actions[0].disabled?.reason, extractLinkDef_1.MdExtractLinkDefinitionCodeActionProvider.notOnLinkAction.disabled?.reason);
        }
    }));
    test('Should add to existing link block', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](./img.png)`, ``, `[abc]: http:://example.com`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[abc]: http:://example.com`, `[def]: ./img.png`));
    }));
    test('Should use new placeholder if existing is already taken', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](http://example.com?3)`, ``, `[def]: http:://example.com?1`, `[def2]: http:://example.com?2`, `[def4]: http:://example.com?4`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def3]`, ``, `[def]: http:://example.com?1`, `[def2]: http:://example.com?2`, `[def4]: http:://example.com?4`, `[def3]: http://example.com?3`));
    }));
    test('Should preserve title', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](http://example.com "some title")`, ``, `[abc]: http:://example.com`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[abc]: http:://example.com`, `[def]: http://example.com "some title"`));
    }));
    test('Should work for link with leading and trailing whitespace', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](    http://example.com "some title"   )`, ``, `[abc]: http:://example.com`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[abc]: http:://example.com`, `[def]: http://example.com "some title"`));
    }));
    test('Should work for bracketed link paths', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](<path to img.png> "title text")`, ``, `[abc]: http:://example.com`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[abc]: http:://example.com`, `[def]: <path to img.png> "title text"`));
    }));
    test('Should preserve trailing newlines', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[text](/path/to/img.png)`, ``, `[abc]: http:://example.com?abc`, `[xyz]: http:://example.com?xyz`, ``));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[text][def]`, ``, `[abc]: http:://example.com?abc`, `[xyz]: http:://example.com?xyz`, `[def]: /path/to/img.png`, ``));
    }));
    test('Should replace all occurrences of link', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`a [text](/img.png) b`, ``, `# c [text](/img.png)`, ``, `[abc]: http:://example.com?abc`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`a [text][def] b`, ``, `# c [text][def]`, ``, `[abc]: http:://example.com?abc`, `[def]: /img.png`));
    }));
    test('Should not extract occurrences where fragments differ', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`a [text](http://example.com#a)`, `b [text](http://example.com#b)`, `a [text](http://example.com#a)`));
        const actions = await getActions(store, doc, { line: 0, character: 3 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`a [text][def]`, `b [text](http://example.com#b)`, `a [text][def]`, ``, `[def]: http://example.com#a`));
    }));
    test('Extract should take inner link when dealing with nested links', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`[![asset_name](http://example.com)](link)`));
        const actions = await getActions(store, doc, { line: 0, character: 20 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`[![asset_name][def]](link)`, ``, `[def]: http://example.com`));
    }));
    test('Extract should be triggerable with cursor on ! for image links', (0, util_1.withStore)(async (store) => {
        const doc = new inMemoryDocument_1.InMemoryDocument((0, util_1.workspacePath)('test.md'), (0, util_1.joinLines)(`![alt](http://example.com)`));
        const actions = await getActions(store, doc, { line: 0, character: 0 });
        assertActiveActionCount(actions, 1);
        const newContent = (0, util_1.applyActionEdit)(doc, actions[0]);
        assert.strictEqual(newContent, (0, util_1.joinLines)(`![alt][def]`, ``, `[def]: http://example.com`));
    }));
});
//# sourceMappingURL=extractLinkDef.test.js.map