From 7bd9e092aca28d40cb30fc5f66f2f7390280db0b Mon Sep 17 00:00:00 2001 From: Sheetal Nandi Date: Fri, 26 May 2017 17:06:15 -0700 Subject: [PATCH] Make configFile on compiler options as non enumerable --- src/compiler/commandLineParser.ts | 10 +++- src/compiler/types.ts | 2 +- src/harness/compilerRunner.ts | 2 +- src/harness/harness.ts | 2 +- src/harness/rwcRunner.ts | 3 +- .../unittests/cachingInServerLSHost.ts | 2 +- .../unittests/configurationExtension.ts | 7 +-- .../convertCompilerOptionsFromJson.ts | 2 +- src/server/project.ts | 2 +- src/server/session.ts | 52 ++++--------------- src/services/services.ts | 2 +- src/services/transpile.ts | 2 +- src/services/utilities.ts | 12 +++-- 13 files changed, 38 insertions(+), 62 deletions(-) diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 6e2b1e97df7..675df9ed7dc 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1380,6 +1380,13 @@ namespace ts { return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions); } + /*@internal*/ + export function setConfigFileInOptions(options: CompilerOptions, configFile: JsonSourceFile) { + if (configFile) { + Object.defineProperty(options, "configFile", { enumerable: false, writable: false, value: configFile }); + } + } + /** * Parse the contents of a config file from json or json source file (tsconfig.json). * @param json The contents of the config file to parse @@ -1406,8 +1413,7 @@ namespace ts { const { raw } = parsedConfig; const options = extend(existingOptions, parsedConfig.options || {}); options.configFilePath = configFileName; - options.configFile = sourceFile; - + setConfigFileInOptions(options, sourceFile); const { fileNames, wildcardDirectories } = getFileNames(); return { options, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index fe98196cd1b..9d8991fe3d8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3449,7 +3449,7 @@ namespace ts { charset?: string; checkJs?: boolean; /* @internal */ configFilePath?: string; - /* @internal */ configFile?: JsonSourceFile; + /* @internal */ readonly configFile?: JsonSourceFile; declaration?: boolean; declarationDir?: string; /* @internal */ diagnostics?: boolean; diff --git a/src/harness/compilerRunner.ts b/src/harness/compilerRunner.ts index 10f8ec66f3e..9d697f8ffe7 100644 --- a/src/harness/compilerRunner.ts +++ b/src/harness/compilerRunner.ts @@ -82,7 +82,7 @@ class CompilerBaselineRunner extends RunnerBase { if (testCaseContent.tsConfig) { assert.equal(testCaseContent.tsConfig.fileNames.length, 0, `list of files in tsconfig is not currently supported`); - tsConfigOptions = ts.clone(testCaseContent.tsConfig.options); + tsConfigOptions = ts.cloneCompilerOptions(testCaseContent.tsConfig.options); tsConfigFiles.push(this.createHarnessTestFile(testCaseContent.tsConfigFileUnitData, rootDir, ts.combinePaths(rootDir, tsConfigOptions.configFilePath))); } else { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 8630ea52a34..7926ca45100 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -1123,7 +1123,7 @@ namespace Harness { compilerOptions: ts.CompilerOptions, // Current directory is needed for rwcRunner to be able to use currentDirectory defined in json file currentDirectory: string): CompilationOutput { - const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.clone(compilerOptions) : { noResolve: false }; + const options: ts.CompilerOptions & HarnessOptions = compilerOptions ? ts.cloneCompilerOptions(compilerOptions) : { noResolve: false }; options.target = options.target || ts.ScriptTarget.ES3; options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed; options.noErrorTruncation = true; diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts index 6379f829d77..128acb1005d 100644 --- a/src/harness/rwcRunner.ts +++ b/src/harness/rwcRunner.ts @@ -87,6 +87,7 @@ namespace RWC { const configParseResult = ts.parseJsonSourceFileConfigFileContent(parsedTsconfigFileContents, configParseHost, ts.getDirectoryPath(tsconfigFile.path)); fileNames = configParseResult.fileNames; opts.options = ts.extend(opts.options, configParseResult.options); + ts.setConfigFileInOptions(opts.options, configParseResult.options.configFile); } // Load the files @@ -262,4 +263,4 @@ class RWCRunner extends RunnerBase { private runTest(jsonFileName: string) { RWC.runRWCTest(jsonFileName); } -} \ No newline at end of file +} diff --git a/src/harness/unittests/cachingInServerLSHost.ts b/src/harness/unittests/cachingInServerLSHost.ts index 1b87fc848b5..f5b54063df7 100644 --- a/src/harness/unittests/cachingInServerLSHost.ts +++ b/src/harness/unittests/cachingInServerLSHost.ts @@ -158,7 +158,7 @@ namespace ts { // setting compiler options discards module resolution cache fileExistsCalled = false; - const compilerOptions = ts.clone(project.getCompilerOptions()); + const compilerOptions = ts.cloneCompilerOptions(project.getCompilerOptions()); compilerOptions.target = ts.ScriptTarget.ES5; project.setCompilerOptions(compilerOptions); diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts index 4429e9321e4..2d50d2cb2af 100644 --- a/src/harness/unittests/configurationExtension.ts +++ b/src/harness/unittests/configurationExtension.ts @@ -131,14 +131,15 @@ namespace ts { it(name, () => { const parsed = getParseCommandLine(entry); assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n")); - assert.deepEqual(parsed.options, ts.extend(expected, { configFile: undefined })); + assert.deepEqual(parsed.options, expected); assert.deepEqual(parsed.fileNames, expectedFiles); }); it(name + " with jsonSourceFile", () => { const { parsed, jsonSourceFile } = getParseCommandLineJsonSourceFile(entry); assert(!parsed.errors.length, flattenDiagnosticMessageText(parsed.errors[0] && parsed.errors[0].messageText, "\n")); - assert.deepEqual(parsed.options, ts.extend(expected, { configFile: jsonSourceFile })); + assert.deepEqual(parsed.options, expected); + assert.equal(parsed.options.configFile, jsonSourceFile); assert.deepEqual(parsed.fileNames, expectedFiles); }); } @@ -208,4 +209,4 @@ namespace ts { }); }); }); -} \ No newline at end of file +} diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index 00c56a73da5..d1bef4480bc 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -34,11 +34,11 @@ namespace ts { const host: ParseConfigHost = new Utils.MockParseConfigHost("/apath/", true, []); const { options: actualCompilerOptions, errors: actualParseErrors } = parseJsonSourceFileConfigFileContent(result, host, "/apath/", /*existingOptions*/ undefined, configFileName); expectedResult.compilerOptions["configFilePath"] = configFileName; - expectedResult.compilerOptions.configFile = result; const parsedCompilerOptions = JSON.stringify(actualCompilerOptions); const expectedCompilerOptions = JSON.stringify(expectedResult.compilerOptions); assert.equal(parsedCompilerOptions, expectedCompilerOptions); + assert.equal(actualCompilerOptions.configFile, result); const actualErrors = filter(actualParseErrors, error => error.code !== Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code); const expectedErrors = expectedResult.errors; diff --git a/src/server/project.ts b/src/server/project.ts index 11a8af58937..d7e1bb49a6c 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -789,7 +789,7 @@ namespace ts.server { setCompilerOptions(options?: CompilerOptions) { // Avoid manipulating the given options directly - const newOptions = options ? clone(options) : this.getCompilerOptions(); + const newOptions = options ? cloneCompilerOptions(options) : this.getCompilerOptions(); if (!newOptions) { return; } diff --git a/src/server/session.ts b/src/server/session.ts index c6dd342c94f..feb8f7fd528 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -132,20 +132,6 @@ namespace ts.server { return `Content-Length: ${1 + len}\r\n\r\n${json}${newLine}`; } - /** - * Get the compiler options without configFile key - * @param options - */ - function getCompilerOptionsWithoutConfigFile(options: CompilerOptions) { - const result: CompilerOptions = {}; - for (const option in options) { - if (option !== "configFile") { - result[option] = options[option]; - } - } - return result; - } - /** * Allows to schedule next step in multistep operation */ @@ -1670,39 +1656,19 @@ namespace ts.server { }, [CommandNames.SynchronizeProjectList]: (request: protocol.SynchronizeProjectListRequest) => { const result = this.projectService.synchronizeProjectList(request.arguments.knownProjects); - // Remapping of the result is needed if - // - there are project errors - // - options contain configFile - need to remove it from options before serializing - const shouldRemapProjectFilesWithTSDiagnostics = (p: ProjectFilesWithTSDiagnostics) => (p.projectErrors && !!p.projectErrors.length) || (p.info && !!p.info.options.configFile); - if (!some(result, shouldRemapProjectFilesWithTSDiagnostics)) { + if (!result.some(p => p.projectErrors && p.projectErrors.length !== 0)) { return this.requiredResponse(result); } const converted = map(result, p => { - if (shouldRemapProjectFilesWithTSDiagnostics(p)) { - // Map the project errors - const projectErrors = p.projectErrors && p.projectErrors.length ? - this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined) : - p.projectErrors; - - // Remove the configFile in the options before serializing - const info = p.info && !!p.info.options.configFile ? - { - projectName: p.info.projectName, - isInferred: p.info.isInferred, - version: p.info.version, - options: getCompilerOptionsWithoutConfigFile(p.info.options), - languageServiceDisabled: p.info.languageServiceDisabled - } : p.info; - - return { - info, - changes: p.changes, - files: p.files, - projectErrors - }; + if (!p.projectErrors || p.projectErrors.length === 0) { + return p; } - - return p; + return { + info: p.info, + changes: p.changes, + files: p.files, + projectErrors: this.convertToDiagnosticsWithLinePosition(p.projectErrors, /*scriptInfo*/ undefined) + }; }); return this.requiredResponse(converted); }, diff --git a/src/services/services.ts b/src/services/services.ts index 7d5541db12c..34f1a4bfaca 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1292,7 +1292,7 @@ namespace ts { const currentOptions = program.getCompilerOptions(); const newOptions = hostCache.compilationSettings(); // If the compilation settings do no match, then the program is not up-to-date - if (!compareDataObjects(currentOptions, newOptions, "configFile")) { + if (!compareDataObjects(currentOptions, newOptions)) { return false; } diff --git a/src/services/transpile.ts b/src/services/transpile.ts index e10fcc70a64..561c188c6cd 100644 --- a/src/services/transpile.ts +++ b/src/services/transpile.ts @@ -130,7 +130,7 @@ namespace ts { commandLineOptionsStringToEnum = commandLineOptionsStringToEnum || filter(optionDeclarations, o => typeof o.type === "object" && !forEachEntry(o.type, v => typeof v !== "number")); - options = clone(options); + options = cloneCompilerOptions(options); for (const opt of commandLineOptionsStringToEnum) { if (!hasProperty(options, opt.name)) { diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 34b729142a3..8ac429a0af5 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -997,16 +997,18 @@ namespace ts { return false; } - export function compareDataObjects(dst: any, src: any, ignoreKey?: string): boolean { + export function cloneCompilerOptions(options: CompilerOptions): CompilerOptions { + const result = clone(options); + setConfigFileInOptions(result, options && options.configFile); + return result; + } + + export function compareDataObjects(dst: any, src: any): boolean { if (!dst || !src || Object.keys(dst).length !== Object.keys(src).length) { return false; } for (const e in dst) { - if (ignoreKey && ignoreKey === e) { - continue; - } - if (typeof dst[e] === "object") { if (!compareDataObjects(dst[e], src[e])) { return false;