• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1namespace ts {
2    const _chai: typeof import("chai") = require("chai");
3    const expect: typeof _chai.expect = _chai.expect;
4    describe("unittests:: services:: languageService", () => {
5        const files: {[index: string]: string} = {
6            "foo.ts": `import Vue from "./vue";
7import Component from "./vue-class-component";
8import { vueTemplateHtml } from "./variables";
9
10@Component({
11    template: vueTemplateHtml,
12})
13class Carousel<T> extends Vue {
14}`,
15            "variables.ts": `export const vueTemplateHtml = \`<div></div>\`;`,
16            "vue.d.ts": `export namespace Vue { export type Config = { template: string }; }`,
17            "vue-class-component.d.ts": `import Vue from "./vue";
18export function Component(x: Config): any;`
19        };
20
21        function createLanguageService() {
22            return ts.createLanguageService({
23                getCompilationSettings() {
24                    return {};
25                },
26                getScriptFileNames() {
27                    return ["foo.ts", "variables.ts", "vue.d.ts", "vue-class-component.d.ts"];
28                },
29                getScriptVersion(_fileName) {
30                    return "";
31                },
32                getScriptSnapshot(fileName) {
33                    if (fileName === ".ts") {
34                        return ScriptSnapshot.fromString("");
35                    }
36                    return ScriptSnapshot.fromString(files[fileName] || "");
37                },
38                getCurrentDirectory: () => ".",
39                getDefaultLibFileName(options) {
40                    return getDefaultLibFilePath(options);
41                },
42            });
43        }
44        // Regression test for GH #18245 - bug in single line comment writer caused a debug assertion when attempting
45        //  to write an alias to a module's default export was referrenced across files and had no default export
46        it("should be able to create a language service which can respond to deinition requests without throwing", () => {
47            const languageService = createLanguageService();
48            const definitions = languageService.getDefinitionAtPosition("foo.ts", 160); // 160 is the latter `vueTemplateHtml` position
49            expect(definitions).to.exist; // eslint-disable-line @typescript-eslint/no-unused-expressions
50        });
51
52        it("getEmitOutput on language service has way to force dts emit", () => {
53            const languageService = createLanguageService();
54            assert.deepEqual(
55                languageService.getEmitOutput(
56                    "foo.ts",
57                    /*emitOnlyDtsFiles*/ true
58                ),
59                {
60                    emitSkipped: true,
61                    diagnostics: emptyArray,
62                    outputFiles: emptyArray,
63                    exportedModulesFromDeclarationEmit: undefined
64                }
65            );
66
67            assert.deepEqual(
68                languageService.getEmitOutput(
69                    "foo.ts",
70                    /*emitOnlyDtsFiles*/ true,
71                    /*forceDtsEmit*/ true
72                ),
73                {
74                    emitSkipped: false,
75                    diagnostics: emptyArray,
76                    outputFiles: [{
77                        name: "foo.d.ts",
78                        text: "export {};\r\n",
79                        writeByteOrderMark: false
80                    }],
81                    exportedModulesFromDeclarationEmit: undefined
82                }
83            );
84        });
85
86        describe("detects program upto date correctly", () => {
87            function verifyProgramUptoDate(useProjectVersion: boolean) {
88                let projectVersion = "1";
89                const files = new Map<string, { version: string, text: string; }>();
90                files.set("/project/root.ts", { version: "1", text: `import { foo } from "./other"` });
91                files.set("/project/other.ts", { version: "1", text: `export function foo() { }` });
92                files.set("/lib/lib.d.ts", { version: "1", text: projectSystem.libFile.content });
93                const host: LanguageServiceHost = {
94                    useCaseSensitiveFileNames: returnTrue,
95                    getCompilationSettings: getDefaultCompilerOptions,
96                    fileExists: path => files.has(path),
97                    getProjectVersion: !useProjectVersion ? undefined : () => projectVersion,
98                    getScriptFileNames: () => ["/project/root.ts"],
99                    getScriptVersion: path => files.get(path)?.version || "",
100                    getScriptSnapshot: path => {
101                        const text = files.get(path)?.text;
102                        return text ? ScriptSnapshot.fromString(text) : undefined;
103                    },
104                    getCurrentDirectory: () => "/project",
105                    getDefaultLibFileName: () => "/lib/lib.d.ts"
106                };
107                const ls = ts.createLanguageService(host);
108                const program1 = ls.getProgram()!;
109                const program2 = ls.getProgram()!;
110                assert.strictEqual(program1, program2);
111                verifyProgramFiles(program1);
112
113                // Change other
114                projectVersion = "2";
115                files.set("/project/other.ts", { version: "2", text: `export function foo() { } export function bar() { }` });
116                const program3 = ls.getProgram()!;
117                assert.notStrictEqual(program2, program3);
118                verifyProgramFiles(program3);
119
120                // change root
121                projectVersion = "3";
122                files.set("/project/root.ts", { version: "2", text: `import { foo, bar } from "./other"` });
123                const program4 = ls.getProgram()!;
124                assert.notStrictEqual(program3, program4);
125                verifyProgramFiles(program4);
126
127                function verifyProgramFiles(program: Program) {
128                    assert.deepEqual(
129                        program.getSourceFiles().map(f => f.fileName),
130                        ["/lib/lib.d.ts", "/project/other.ts", "/project/root.ts"]
131                    );
132                }
133            }
134            it("when host implements getProjectVersion", () => {
135                verifyProgramUptoDate(/*useProjectVersion*/ true);
136            });
137            it("when host does not implement getProjectVersion", () => {
138                verifyProgramUptoDate(/*useProjectVersion*/ false);
139            });
140        });
141    });
142}
143