diff --git a/Jakefile.js b/Jakefile.js index b3e18e8cb1a..ad853238111 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -143,6 +143,7 @@ var harnessSources = harnessCoreSources.concat([ "customTransforms.ts", "programMissingFiles.ts", "symbolWalker.ts", + "languageService.ts", ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 2a07d2b6560..725070c02bf 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -32,7 +32,6 @@ namespace ts { } const stringWriter = createSingleLineStringWriter(); - let stringWriterAcquired = false; function createSingleLineStringWriter(): StringSymbolWriter { let str = ""; @@ -62,15 +61,14 @@ namespace ts { } export function usingSingleLineStringWriter(action: (writer: StringSymbolWriter) => void): string { + const oldString = stringWriter.string(); try { - Debug.assert(!stringWriterAcquired); - stringWriterAcquired = true; action(stringWriter); return stringWriter.string(); } finally { stringWriter.clear(); - stringWriterAcquired = false; + stringWriter.writeKeyword(oldString); } } diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json index 1469079bcaa..bd7c9bc2ffa 100644 --- a/src/harness/tsconfig.json +++ b/src/harness/tsconfig.json @@ -128,6 +128,7 @@ "./unittests/extractMethods.ts", "./unittests/textChanges.ts", "./unittests/telemetry.ts", + "./unittests/languageService.ts", "./unittests/programMissingFiles.ts" ] } diff --git a/src/harness/unittests/languageService.ts b/src/harness/unittests/languageService.ts new file mode 100644 index 00000000000..9c838845c20 --- /dev/null +++ b/src/harness/unittests/languageService.ts @@ -0,0 +1,49 @@ +/// + +namespace ts { + describe("languageService", () => { + const files: {[index: string]: string} = { + "foo.ts": `import Vue from "./vue"; +import Component from "./vue-class-component"; +import { vueTemplateHtml } from "./variables"; + +@Component({ + template: vueTemplateHtml, +}) +class Carousel extends Vue { +}`, + "variables.ts": `export const vueTemplateHtml = \`
\`;`, + "vue.d.ts": `export namespace Vue { export type Config = { template: string }; }`, + "vue-class-component.d.ts": `import Vue from "./vue"; +export function Component(x: Config): any;` +}; + it("should be able to create a language service which can respond to deinition requests without throwing", () => { + const languageService = ts.createLanguageService({ + getCompilationSettings() { + return {}; + }, + getScriptFileNames() { + return ["foo.ts", "variables.ts", "vue.d.ts", "vue-class-component.d.ts"]; + }, + getScriptVersion(_fileName) { + return ""; + }, + getScriptSnapshot(fileName) { + if (fileName === ".ts") { + return ts.ScriptSnapshot.fromString(""); + } + return ts.ScriptSnapshot.fromString(files[fileName] || ""); + }, + getCurrentDirectory: () => ".", + getDefaultLibFileName(options) { + return ts.getDefaultLibFilePath(options); + }, + fileExists: noop as any, + readFile: noop as any, + readDirectory: noop as any, + }); + const definitions = languageService.getDefinitionAtPosition("foo.ts", 160); // 160 is the latter `vueTemplateHtml` position + expect(definitions).to.exist; + }); + }); +} \ No newline at end of file