"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 fs_1 = __importDefault(require("fs"));
const path = __importStar(require("path"));
const typescript_1 = __importDefault(require("typescript"));
const vscode_languageserver_1 = require("vscode-languageserver");
const documents_1 = require("../../../src/lib/documents");
const ls_config_1 = require("../../../src/ls-config");
const plugins_1 = require("../../../src/plugins");
const DocumentSnapshot_1 = require("../../../src/plugins/typescript/DocumentSnapshot");
const service_1 = require("../../../src/plugins/typescript/service");
const SnapshotManager_1 = require("../../../src/plugins/typescript/SnapshotManager");
const utils_1 = require("../../../src/utils");
const test_utils_1 = require("./test-utils");
const svelte2tsx_1 = require("svelte2tsx");
const compiler_1 = require("svelte/compiler");
const testDir = path.join(__dirname, 'testfiles');
describe('TypescriptPlugin', function () {
    (0, test_utils_1.serviceWarmup)(this, testDir);
    function getUri(filename) {
        const filePath = path.join(__dirname, 'testfiles', filename);
        return (0, utils_1.pathToUrl)(filePath);
    }
    function harmonizeNewLines(input) {
        return input.replace(/\r\n/g, '~:~').replace(/\n/g, '~:~').replace(/~:~/g, '\n');
    }
    function setup(filename) {
        const docManager = new documents_1.DocumentManager((args) => args.uri.includes('.svelte')
            ? new documents_1.Document(args.uri, harmonizeNewLines(args.text))
            : document);
        const filePath = path.join(testDir, filename);
        const document = new documents_1.Document((0, utils_1.pathToUrl)(filePath), typescript_1.default.sys.readFile(filePath) || '');
        const lsConfigManager = new ls_config_1.LSConfigManager();
        const workspaceUris = [(0, utils_1.pathToUrl)(testDir)];
        const lsAndTsDocResolver = new plugins_1.LSAndTSDocResolver(docManager, workspaceUris, lsConfigManager, {
            nonRecursiveWatchPattern: '**/*.{ts,js}'
        });
        const plugin = new plugins_1.TypeScriptPlugin(lsConfigManager, lsAndTsDocResolver, workspaceUris, docManager);
        docManager.openClientDocument('some doc');
        return { plugin, document, lsAndTsDocResolver, docManager };
    }
    it('provides document symbols', async () => {
        const { plugin, document } = setup('documentsymbols.svelte');
        let symbols = await plugin.getDocumentSymbols(document);
        symbols = symbols
            .map((s) => ({ ...s, name: harmonizeNewLines(s.name) }))
            .sort((s1, s2) => s1.location.range.start.line * 100 +
            s1.location.range.start.character -
            (s2.location.range.start.line * 100 + s2.location.range.start.character));
        assert.deepStrictEqual(symbols, [
            {
                name: 'bla',
                kind: 12,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 1,
                            character: 2
                        },
                        end: {
                            line: 3,
                            character: 3
                        }
                    }
                },
                containerName: svelte2tsx_1.internalHelpers.renderName
            },
            {
                name: 'hello',
                kind: 13,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 5,
                            character: 5
                        },
                        end: {
                            line: 5,
                            character: 14
                        }
                    }
                },
                containerName: svelte2tsx_1.internalHelpers.renderName
            },
            {
                name: "$: if (hello) {\n    console.log('hi');\n  }",
                kind: 12,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 6,
                            character: 1
                        },
                        end: {
                            line: 8,
                            character: 3
                        }
                    }
                },
                containerName: svelte2tsx_1.internalHelpers.renderName
            },
            {
                name: '$on("click") callback',
                kind: 12,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 12,
                            character: 39
                        },
                        end: {
                            line: 12,
                            character: 47
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'x',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 13,
                            character: 15
                        },
                        end: {
                            line: 13,
                            character: 16
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'b',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 13,
                            character: 21
                        },
                        end: {
                            line: 13,
                            character: 25
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'x',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 14,
                            character: 21
                        },
                        end: {
                            line: 14,
                            character: 22
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'b',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 14,
                            character: 27
                        },
                        end: {
                            line: 14,
                            character: 31
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'foo',
                kind: 13,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 16,
                            character: 17
                        },
                        end: {
                            line: 16,
                            character: 20
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'bar',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 17,
                            character: 10
                        },
                        end: {
                            line: 17,
                            character: 19
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'result',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 20,
                            character: 15
                        },
                        end: {
                            line: 20,
                            character: 21
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'bar',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 21,
                            character: 10
                        },
                        end: {
                            line: 21,
                            character: 22
                        }
                    }
                },
                containerName: '<function>'
            },
            {
                name: 'error',
                kind: 14,
                location: {
                    uri: getUri('documentsymbols.svelte'),
                    range: {
                        start: {
                            line: 23,
                            character: 8
                        },
                        end: {
                            line: 23,
                            character: 13
                        }
                    }
                },
                containerName: '<function>'
            }
        ]);
    });
    it('can cancel document symbols before promise resolved', async () => {
        const { plugin, document } = setup('documentsymbols.svelte');
        const cancellationTokenSource = new vscode_languageserver_1.CancellationTokenSource();
        const symbolsPromise = plugin.getDocumentSymbols(document, cancellationTokenSource.token);
        cancellationTokenSource.cancel();
        assert.deepStrictEqual(await symbolsPromise, []);
    });
    it('provides definitions within svelte doc', async () => {
        const { plugin, document } = setup('definitions.svelte');
        const definitions = await plugin.getDefinitions(document, vscode_languageserver_1.Position.create(4, 1));
        assert.deepStrictEqual(definitions, [
            {
                originSelectionRange: {
                    start: {
                        character: 0,
                        line: 4
                    },
                    end: {
                        character: 3,
                        line: 4
                    }
                },
                targetRange: {
                    start: {
                        character: 9,
                        line: 3
                    },
                    end: {
                        character: 12,
                        line: 3
                    }
                },
                targetSelectionRange: {
                    start: {
                        character: 9,
                        line: 3
                    },
                    end: {
                        character: 12,
                        line: 3
                    }
                },
                targetUri: getUri('definitions.svelte')
            }
        ]);
    });
    it('provides definitions from svelte to ts doc', async () => {
        const { plugin, document } = setup('definitions.svelte');
        const definitions = await plugin.getDefinitions(document, vscode_languageserver_1.Position.create(5, 1));
        assert.deepStrictEqual(definitions, [
            {
                originSelectionRange: {
                    start: {
                        character: 0,
                        line: 5
                    },
                    end: {
                        character: 5,
                        line: 5
                    }
                },
                targetRange: {
                    start: {
                        character: 16,
                        line: 0
                    },
                    end: {
                        character: 21,
                        line: 0
                    }
                },
                targetSelectionRange: {
                    start: {
                        character: 16,
                        line: 0
                    },
                    end: {
                        character: 21,
                        line: 0
                    }
                },
                targetUri: getUri('definitions.ts')
            }
        ]);
    });
    it('provides definitions from svelte to svelte doc', async () => {
        const { plugin, document } = setup('definitions.svelte');
        const definitions = await plugin.getDefinitions(document, vscode_languageserver_1.Position.create(12, 3));
        assert.deepStrictEqual(definitions, [
            {
                originSelectionRange: {
                    start: {
                        character: 1,
                        line: 12
                    },
                    end: {
                        character: 13,
                        line: 12
                    }
                },
                targetRange: {
                    start: {
                        character: 1,
                        line: 0
                    },
                    end: {
                        character: 1,
                        line: 0
                    }
                },
                targetSelectionRange: {
                    start: {
                        character: 1,
                        line: 0
                    },
                    end: {
                        character: 1,
                        line: 0
                    }
                },
                targetUri: getUri('imported-file.svelte')
            }
        ]);
    });
    describe('provides definitions for $store within svelte file', () => {
        async function test$StoreDef(pos, originSelectionRange) {
            const { plugin, document } = setup('definitions.svelte');
            const definitions = await plugin.getDefinitions(document, pos);
            assert.deepStrictEqual(definitions, [
                {
                    originSelectionRange,
                    targetRange: {
                        start: {
                            character: 4,
                            line: 6
                        },
                        end: {
                            character: 9,
                            line: 6
                        }
                    },
                    targetSelectionRange: {
                        start: {
                            character: 4,
                            line: 6
                        },
                        end: {
                            character: 9,
                            line: 6
                        }
                    },
                    targetUri: getUri('definitions.svelte')
                }
            ]);
        }
        it('(within script simple)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(7, 1), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(7, 0), vscode_languageserver_1.Position.create(7, 6)));
        });
        it('(within script if)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(8, 7), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(8, 4), vscode_languageserver_1.Position.create(8, 10)));
        });
        it('(within template simple)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(13, 3), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(13, 1), vscode_languageserver_1.Position.create(13, 7)));
        });
        it('(within template if)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(14, 7), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(14, 5), vscode_languageserver_1.Position.create(14, 11)));
        });
    });
    describe('provides definitions for $store from svelte file to ts file', () => {
        async function test$StoreDef(pos, originSelectionRange) {
            const { plugin, document } = setup('definitions.svelte');
            const definitions = await plugin.getDefinitions(document, pos);
            assert.deepStrictEqual(definitions, [
                {
                    originSelectionRange,
                    targetRange: {
                        start: {
                            character: 16,
                            line: 0
                        },
                        end: {
                            character: 21,
                            line: 0
                        }
                    },
                    targetSelectionRange: {
                        start: {
                            character: 16,
                            line: 0
                        },
                        end: {
                            character: 21,
                            line: 0
                        }
                    },
                    targetUri: getUri('definitions.ts')
                }
            ]);
        }
        it('(within script simple)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(9, 1), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(9, 0), vscode_languageserver_1.Position.create(9, 6)));
        });
        it('(within script if)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(10, 7), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(10, 4), vscode_languageserver_1.Position.create(10, 10)));
        });
        it('(within template simple)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(16, 3), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(16, 1), vscode_languageserver_1.Position.create(16, 7)));
        });
        it('(within template if)', async () => {
            await test$StoreDef(vscode_languageserver_1.Position.create(17, 7), vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(17, 5), vscode_languageserver_1.Position.create(17, 11)));
        });
    });
    it('map definition of dts with declarationMap to source ', async () => {
        const { plugin, document } = setup('declaration-map/importing.svelte');
        const definition = await plugin.getDefinitions(document, { line: 1, character: 13 });
        assert.deepStrictEqual(definition, [
            {
                targetRange: {
                    end: { line: 0, character: 18 },
                    start: { line: 0, character: 16 }
                },
                targetSelectionRange: {
                    start: { line: 0, character: 16 },
                    end: { line: 0, character: 18 }
                },
                originSelectionRange: {
                    start: { line: 1, character: 13 },
                    end: { line: 1, character: 15 }
                },
                targetUri: getUri('declaration-map/declaration-map-project/index.ts')
            }
        ]);
    });
    it('map definition of dts with declarationMap (base64 data url) to source ', async () => {
        const { plugin, document } = setup('declaration-map/import-from-base64-sourcemap.svelte');
        const definition = await plugin.getDefinitions(document, { line: 1, character: 13 });
        assert.deepStrictEqual(definition, [
            {
                targetRange: {
                    end: { line: 0, character: 18 },
                    start: { line: 0, character: 16 }
                },
                targetSelectionRange: {
                    start: { line: 0, character: 16 },
                    end: { line: 0, character: 18 }
                },
                originSelectionRange: {
                    start: { line: 1, character: 13 },
                    end: { line: 1, character: 15 }
                },
                targetUri: getUri('declaration-map/declaration-map-project/index.ts')
            }
        ]);
    });
    const setupForOnWatchedFileChanges = async () => {
        const { plugin, document, lsAndTsDocResolver, docManager } = setup('empty.svelte');
        const targetSvelteFile = document.getFilePath();
        const snapshotManager = (await lsAndTsDocResolver.getTSService(targetSvelteFile))
            .snapshotManager;
        return {
            snapshotManager,
            plugin,
            targetSvelteFile,
            lsAndTsDocResolver,
            docManager
        };
    };
    const setupForOnWatchedFileUpdateOrDelete = async () => {
        const { plugin, snapshotManager, targetSvelteFile } = await setupForOnWatchedFileChanges();
        const projectJsFile = path.join(path.dirname(targetSvelteFile), 'documentation.ts');
        await plugin.onWatchFileChanges([
            {
                fileName: projectJsFile,
                changeType: vscode_languageserver_1.FileChangeType.Changed
            }
        ]);
        return {
            snapshotManager,
            plugin,
            projectJsFile
        };
    };
    it('bumps snapshot version when watched file changes', async () => {
        const { snapshotManager, projectJsFile, plugin } = await setupForOnWatchedFileUpdateOrDelete();
        const firstSnapshot = snapshotManager.get(projectJsFile);
        const firstVersion = firstSnapshot?.version;
        assert.notEqual(firstVersion, DocumentSnapshot_1.INITIAL_VERSION);
        await plugin.onWatchFileChanges([
            {
                fileName: projectJsFile,
                changeType: vscode_languageserver_1.FileChangeType.Changed
            }
        ]);
        const secondSnapshot = snapshotManager.get(projectJsFile);
        assert.notEqual(secondSnapshot?.version, firstVersion);
    });
    it('should delete snapshot cache when file delete', async () => {
        const { snapshotManager, projectJsFile, plugin } = await setupForOnWatchedFileUpdateOrDelete();
        const firstSnapshot = snapshotManager.get(projectJsFile);
        assert.notEqual(firstSnapshot, undefined);
        await plugin.onWatchFileChanges([
            {
                fileName: projectJsFile,
                changeType: vscode_languageserver_1.FileChangeType.Deleted
            }
        ]);
        const secondSnapshot = snapshotManager.get(projectJsFile);
        assert.equal(secondSnapshot, undefined);
    });
    const testForOnWatchedFileAdd = async (filePath, shouldExist) => {
        const { snapshotManager, plugin, targetSvelteFile, lsAndTsDocResolver } = await setupForOnWatchedFileChanges();
        const addFile = path.join(path.dirname(targetSvelteFile), filePath);
        const dir = path.dirname(addFile);
        if (!fs_1.default.existsSync(dir)) {
            fs_1.default.mkdirSync(dir);
        }
        fs_1.default.writeFileSync(addFile, 'export function abc() {}');
        assert.ok(fs_1.default.existsSync(addFile));
        try {
            assert.equal(snapshotManager.has(addFile), false);
            await plugin.onWatchFileChanges([
                {
                    fileName: addFile,
                    changeType: vscode_languageserver_1.FileChangeType.Created
                }
            ]);
            (await lsAndTsDocResolver.getTSService(targetSvelteFile)).getService();
            assert.equal(snapshotManager.has(addFile), shouldExist);
            await plugin.onWatchFileChanges([
                {
                    fileName: addFile,
                    changeType: vscode_languageserver_1.FileChangeType.Changed
                }
            ]);
            assert.equal(snapshotManager.has(addFile), shouldExist);
        }
        finally {
            fs_1.default.unlinkSync(addFile);
        }
    };
    it('should add snapshot when a project file is added', async () => {
        await testForOnWatchedFileAdd('foo.ts', true);
    });
    it('should not add snapshot when an excluded file is added', async () => {
        await testForOnWatchedFileAdd(path.join('dist', 'index.js'), false);
    });
    it('should not add snapshot when files added to known build directory', async () => {
        for (const dir of SnapshotManager_1.ignoredBuildDirectories) {
            await testForOnWatchedFileAdd(path.join(dir, 'index.js'), false);
        }
    });
    it('should add declaration file snapshot when added to known build directory', async () => {
        await testForOnWatchedFileAdd(path.join('.svelte-kit', 'ambient.d.ts'), true);
    });
    it('should update ts/js file after document change', async () => {
        const { snapshotManager, projectJsFile, plugin } = await setupForOnWatchedFileUpdateOrDelete();
        const firstSnapshot = snapshotManager.get(projectJsFile);
        const firstVersion = firstSnapshot?.version;
        const firstText = firstSnapshot?.getText(0, firstSnapshot?.getLength());
        assert.notEqual(firstVersion, DocumentSnapshot_1.INITIAL_VERSION);
        await plugin.updateTsOrJsFile(projectJsFile, [
            {
                range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
                text: 'const = "hello world";'
            }
        ]);
        const secondSnapshot = snapshotManager.get(projectJsFile);
        assert.notEqual(secondSnapshot?.version, firstVersion);
        assert.equal(secondSnapshot?.getText(0, secondSnapshot?.getLength()), 'const = "hello world";' + firstText);
    });
    it("shouldn't close svelte document when renamed", async () => {
        const { plugin, docManager, targetSvelteFile } = await setupForOnWatchedFileChanges();
        docManager.openClientDocument({
            text: '',
            uri: (0, utils_1.pathToUrl)(targetSvelteFile)
        });
        const basename = path.basename(targetSvelteFile);
        const newFileName = basename.replace('.svelte', '').toUpperCase() + '.svelte';
        const newFilePath = path.join(path.dirname(targetSvelteFile), newFileName);
        await plugin.onWatchFileChanges([
            {
                fileName: targetSvelteFile,
                changeType: vscode_languageserver_1.FileChangeType.Deleted
            },
            {
                fileName: newFilePath,
                changeType: vscode_languageserver_1.FileChangeType.Created
            }
        ]);
        const document = docManager.get((0, utils_1.pathToUrl)(targetSvelteFile));
        assert.ok(document);
    });
    it("shouldn't mark client svelte document as close", async () => {
        const { plugin, docManager, targetSvelteFile } = await setupForOnWatchedFileChanges();
        docManager.openClientDocument({
            text: '',
            uri: (0, utils_1.pathToUrl)(targetSvelteFile)
        });
        await plugin.onWatchFileChanges([
            {
                fileName: targetSvelteFile,
                changeType: vscode_languageserver_1.FileChangeType.Changed
            }
        ]);
        const document = docManager.get((0, utils_1.pathToUrl)(targetSvelteFile));
        assert.equal(document?.openedByClient, true);
    });
    // Hacky, but it works. Needed due to testing both new and old transformation
    after(() => {
        (0, service_1.__resetCache)();
    });
    const isSvelte5Plus = Number(compiler_1.VERSION.split('.')[0]) >= 5;
    if (!isSvelte5Plus) {
        return;
    }
    it('provides definitions from svelte to rune-mode svelte doc', async () => {
        const { plugin, document } = setup('definition/definition-rune.svelte');
        const definitions = await plugin.getDefinitions(document, vscode_languageserver_1.Position.create(4, 3));
        assert.deepStrictEqual(definitions, [
            {
                originSelectionRange: {
                    start: {
                        character: 1,
                        line: 4
                    },
                    end: {
                        character: 13,
                        line: 4
                    }
                },
                targetRange: {
                    start: {
                        character: 1,
                        line: 0
                    },
                    end: {
                        character: 1,
                        line: 0
                    }
                },
                targetSelectionRange: {
                    start: {
                        character: 1,
                        line: 0
                    },
                    end: {
                        character: 1,
                        line: 0
                    }
                },
                targetUri: getUri('definition/imported-rune.svelte')
            }
        ]);
    });
});
//# sourceMappingURL=TypescriptPlugin.test.js.map