diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 64546188a88f4..decc8751453a6 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -15,6 +15,7 @@ import { CommandLineOptionOfListType, CompilerOptions, CompilerOptionsValue, + computedOptions, ConfigFileSpecs, containsPath, convertToRelativePath, @@ -103,6 +104,7 @@ import { removeTrailingDirectorySeparator, returnTrue, ScriptTarget, + some, startsWith, StringLiteral, SyntaxKind, @@ -2475,9 +2477,10 @@ export function convertToTSConfig(configParseResult: ParsedCommandLine, configFi ), f => getRelativePathFromFile(getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), getNormalizedAbsolutePath(f, host.getCurrentDirectory()), getCanonicalFileName), ); - const optionMap = serializeCompilerOptions(configParseResult.options, { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }); + const pathOptions = { configFilePath: getNormalizedAbsolutePath(configFileName, host.getCurrentDirectory()), useCaseSensitiveFileNames: host.useCaseSensitiveFileNames }; + const optionMap = serializeCompilerOptions(configParseResult.options, pathOptions); const watchOptionMap = configParseResult.watchOptions && serializeWatchOptions(configParseResult.watchOptions); - const config = { + const config: TSConfig & { watchOptions?: object; } = { compilerOptions: { ...optionMapToObject(optionMap), showConfig: undefined, @@ -2500,6 +2503,19 @@ export function convertToTSConfig(configParseResult: ParsedCommandLine, configFi } : {}), compileOnSave: !!configParseResult.compileOnSave ? true : undefined, }; + + const providedKeys = new Set(optionMap.keys()); + const impliedCompilerOptions: Record = {}; + for (const option in computedOptions) { + if (!providedKeys.has(option) && some(computedOptions[option as keyof typeof computedOptions].dependencies, dep => providedKeys.has(dep))) { + const implied = computedOptions[option as keyof typeof computedOptions].computeValue(configParseResult.options); + const defaultValue = computedOptions[option as keyof typeof computedOptions].computeValue({}); + if (implied !== defaultValue) { + impliedCompilerOptions[option] = computedOptions[option as keyof typeof computedOptions].computeValue(configParseResult.options); + } + } + } + assign(config.compilerOptions, optionMapToObject(serializeCompilerOptions(impliedCompilerOptions, pathOptions))); return config; } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 68a538d7b9804..0041530d3ae18 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8588,51 +8588,176 @@ export function getSetExternalModuleIndicator(options: CompilerOptions): (file: } /** @internal */ -export function getEmitScriptTarget(compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }): ScriptTarget { - return compilerOptions.target ?? - ((compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) || - (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) || - ScriptTarget.ES5); -} +export interface ComputedCompilerOption { + name: N; + dependencies: readonly K[]; + computeValue: (compilerOptions: Pick) => R; +} + +/** @internal */ +function computedCompilerOption( + name: N, + dependencies: readonly K[], + computeValue: (compilerOptions: Pick) => R, +): ComputedCompilerOption { + return { name, dependencies, computeValue }; +} + +/** @internal */ +export const computedOptions = { + target: computedCompilerOption("target", ["module"], compilerOptions => { + return compilerOptions.target ?? + ((compilerOptions.module === ModuleKind.Node16 && ScriptTarget.ES2022) || + (compilerOptions.module === ModuleKind.NodeNext && ScriptTarget.ESNext) || + ScriptTarget.ES5); + }), + module: computedCompilerOption("module", ["target"], (compilerOptions): ModuleKind => { + return typeof compilerOptions.module === "number" ? + compilerOptions.module : + computedOptions.target.computeValue(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; + }), + moduleResolution: computedCompilerOption("moduleResolution", ["module", "target"], (compilerOptions): ModuleResolutionKind => { + let moduleResolution = compilerOptions.moduleResolution; + if (moduleResolution === undefined) { + switch (computedOptions.module.computeValue(compilerOptions)) { + case ModuleKind.CommonJS: + moduleResolution = ModuleResolutionKind.Node10; + break; + case ModuleKind.Node16: + moduleResolution = ModuleResolutionKind.Node16; + break; + case ModuleKind.NodeNext: + moduleResolution = ModuleResolutionKind.NodeNext; + break; + default: + moduleResolution = ModuleResolutionKind.Classic; + break; + } + } + return moduleResolution; + }), + moduleDetection: computedCompilerOption("moduleDetection", ["module", "target"], (compilerOptions): ModuleDetectionKind => { + return compilerOptions.moduleDetection || + (computedOptions.module.computeValue(compilerOptions) === ModuleKind.Node16 || + computedOptions.module.computeValue(compilerOptions) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); + }), + isolatedModules: computedCompilerOption("isolatedModules", ["verbatimModuleSyntax"], compilerOptions => { + return !!(compilerOptions.isolatedModules || compilerOptions.verbatimModuleSyntax); + }), + esModuleInterop: computedCompilerOption("esModuleInterop", ["module", "target"], (compilerOptions): boolean | undefined => { + if (compilerOptions.esModuleInterop !== undefined) { + return compilerOptions.esModuleInterop; + } + switch (computedOptions.module.computeValue(compilerOptions)) { + case ModuleKind.Node16: + case ModuleKind.NodeNext: + return true; + } + }), + allowSyntheticDefaultImports: computedCompilerOption("allowSyntheticDefaultImports", ["module", "target", "moduleResolution"], (compilerOptions): boolean => { + if (compilerOptions.allowSyntheticDefaultImports !== undefined) { + return compilerOptions.allowSyntheticDefaultImports; + } + return computedOptions.esModuleInterop.computeValue(compilerOptions) + || computedOptions.module.computeValue(compilerOptions) === ModuleKind.System + || computedOptions.moduleResolution.computeValue(compilerOptions) === ModuleResolutionKind.Bundler; + }), + resolvePackageJsonExports: computedCompilerOption("resolvePackageJsonExports", ["moduleResolution"], (compilerOptions): boolean => { + const moduleResolution = computedOptions.moduleResolution.computeValue(compilerOptions); + if (!moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { + return false; + } + if (compilerOptions.resolvePackageJsonExports !== undefined) { + return compilerOptions.resolvePackageJsonExports; + } + switch (moduleResolution) { + case ModuleResolutionKind.Node16: + case ModuleResolutionKind.NodeNext: + case ModuleResolutionKind.Bundler: + return true; + } + return false; + }), + resolvePackageJsonImports: computedCompilerOption("resolvePackageJsonImports", ["moduleResolution", "resolvePackageJsonExports"], (compilerOptions): boolean => { + const moduleResolution = computedOptions.moduleResolution.computeValue(compilerOptions); + if (!moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { + return false; + } + if (compilerOptions.resolvePackageJsonExports !== undefined) { + return compilerOptions.resolvePackageJsonExports; + } + switch (moduleResolution) { + case ModuleResolutionKind.Node16: + case ModuleResolutionKind.NodeNext: + case ModuleResolutionKind.Bundler: + return true; + } + return false; + }), + resolveJsonModule: computedCompilerOption("resolveJsonModule", ["moduleResolution", "module", "target"], (compilerOptions): boolean | undefined => { + if (compilerOptions.resolveJsonModule !== undefined) { + return compilerOptions.resolveJsonModule; + } + return computedOptions.moduleResolution.computeValue(compilerOptions) === ModuleResolutionKind.Bundler; + }), + declaration: computedCompilerOption("declaration", ["composite"], compilerOptions => { + return !!(compilerOptions.declaration || compilerOptions.composite); + }), + preserveConstEnums: computedCompilerOption("preserveConstEnums", ["isolatedModules", "verbatimModuleSyntax"], (compilerOptions): boolean => { + return !!(compilerOptions.preserveConstEnums || computedOptions.isolatedModules.computeValue(compilerOptions)); + }), + incremental: computedCompilerOption("incremental", ["composite"], compilerOptions => { + return !!(compilerOptions.incremental || compilerOptions.composite); + }), + declarationMap: computedCompilerOption("declarationMap", ["declaration", "composite"], (compilerOptions): boolean => { + return !!(compilerOptions.declarationMap && computedOptions.declaration.computeValue(compilerOptions)); + }), + allowJs: computedCompilerOption("allowJs", ["checkJs"], compilerOptions => { + return compilerOptions.allowJs === undefined ? !!compilerOptions.checkJs : compilerOptions.allowJs; + }), + useDefineForClassFields: computedCompilerOption("useDefineForClassFields", ["target", "module"], (compilerOptions): boolean => { + return compilerOptions.useDefineForClassFields === undefined + ? computedOptions.target.computeValue(compilerOptions) >= ScriptTarget.ES2022 + : compilerOptions.useDefineForClassFields; + }), +}; /** @internal */ -export function getEmitModuleKind(compilerOptions: { module?: CompilerOptions["module"]; target?: CompilerOptions["target"]; }) { - return typeof compilerOptions.module === "number" ? - compilerOptions.module : - getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2015 ? ModuleKind.ES2015 : ModuleKind.CommonJS; -} - +export const getEmitScriptTarget = computedOptions.target.computeValue; /** @internal */ -export function emitModuleKindIsNonNodeESM(moduleKind: ModuleKind) { - return moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext; -} - +export const getEmitModuleKind = computedOptions.module.computeValue; /** @internal */ -export function getEmitModuleResolutionKind(compilerOptions: CompilerOptions) { - let moduleResolution = compilerOptions.moduleResolution; - if (moduleResolution === undefined) { - switch (getEmitModuleKind(compilerOptions)) { - case ModuleKind.CommonJS: - moduleResolution = ModuleResolutionKind.Node10; - break; - case ModuleKind.Node16: - moduleResolution = ModuleResolutionKind.Node16; - break; - case ModuleKind.NodeNext: - moduleResolution = ModuleResolutionKind.NodeNext; - break; - default: - moduleResolution = ModuleResolutionKind.Classic; - break; - } - } - return moduleResolution; -} +export const getEmitModuleResolutionKind = computedOptions.moduleResolution.computeValue; +/** @internal */ +export const getEmitModuleDetectionKind = computedOptions.moduleDetection.computeValue; +/** @internal */ +export const getIsolatedModules = computedOptions.isolatedModules.computeValue; +/** @internal */ +export const getESModuleInterop = computedOptions.esModuleInterop.computeValue; +/** @internal */ +export const getAllowSyntheticDefaultImports = computedOptions.allowSyntheticDefaultImports.computeValue; +/** @internal */ +export const getResolvePackageJsonExports = computedOptions.resolvePackageJsonExports.computeValue; +/** @internal */ +export const getResolvePackageJsonImports = computedOptions.resolvePackageJsonImports.computeValue; +/** @internal */ +export const getResolveJsonModule = computedOptions.resolveJsonModule.computeValue; +/** @internal */ +export const getEmitDeclarations = computedOptions.declaration.computeValue; +/** @internal */ +export const shouldPreserveConstEnums = computedOptions.preserveConstEnums.computeValue; +/** @internal */ +export const isIncrementalCompilation = computedOptions.incremental.computeValue; +/** @internal */ +export const getAreDeclarationMapsEnabled = computedOptions.declarationMap.computeValue; +/** @internal */ +export const getAllowJSCompilerOption = computedOptions.allowJs.computeValue; +/** @internal */ +export const getUseDefineForClassFields = computedOptions.useDefineForClassFields.computeValue; /** @internal */ -export function getEmitModuleDetectionKind(options: CompilerOptions) { - return options.moduleDetection || - (getEmitModuleKind(options) === ModuleKind.Node16 || getEmitModuleKind(options) === ModuleKind.NodeNext ? ModuleDetectionKind.Force : ModuleDetectionKind.Auto); +export function emitModuleKindIsNonNodeESM(moduleKind: ModuleKind) { + return moduleKind >= ModuleKind.ES2015 && moduleKind <= ModuleKind.ESNext; } /** @internal */ @@ -8652,11 +8777,6 @@ export function hasJsonModuleEmitEnabled(options: CompilerOptions) { } } -/** @internal */ -export function getIsolatedModules(options: CompilerOptions) { - return !!(options.isolatedModules || options.verbatimModuleSyntax); -} - /** @internal */ export function importNameElisionDisabled(options: CompilerOptions) { return options.verbatimModuleSyntax || options.isolatedModules && options.preserveValueImports; @@ -8672,34 +8792,6 @@ export function unusedLabelIsError(options: CompilerOptions): boolean { return options.allowUnusedLabels === false; } -/** @internal */ -export function getAreDeclarationMapsEnabled(options: CompilerOptions) { - return !!(getEmitDeclarations(options) && options.declarationMap); -} - -/** @internal */ -export function getESModuleInterop(compilerOptions: CompilerOptions) { - if (compilerOptions.esModuleInterop !== undefined) { - return compilerOptions.esModuleInterop; - } - switch (getEmitModuleKind(compilerOptions)) { - case ModuleKind.Node16: - case ModuleKind.NodeNext: - return true; - } - return undefined; -} - -/** @internal */ -export function getAllowSyntheticDefaultImports(compilerOptions: CompilerOptions) { - if (compilerOptions.allowSyntheticDefaultImports !== undefined) { - return compilerOptions.allowSyntheticDefaultImports; - } - return getESModuleInterop(compilerOptions) - || getEmitModuleKind(compilerOptions) === ModuleKind.System - || getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler; -} - /** @internal */ export function moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution: ModuleResolutionKind): boolean { return moduleResolution >= ModuleResolutionKind.Node16 && moduleResolution <= ModuleResolutionKind.NodeNext @@ -8712,65 +8804,6 @@ export function shouldResolveJsRequire(compilerOptions: CompilerOptions): boolea return !!compilerOptions.noDtsResolution || getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.Bundler; } -/** @internal */ -export function getResolvePackageJsonExports(compilerOptions: CompilerOptions) { - const moduleResolution = getEmitModuleResolutionKind(compilerOptions); - if (!moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { - return false; - } - if (compilerOptions.resolvePackageJsonExports !== undefined) { - return compilerOptions.resolvePackageJsonExports; - } - switch (moduleResolution) { - case ModuleResolutionKind.Node16: - case ModuleResolutionKind.NodeNext: - case ModuleResolutionKind.Bundler: - return true; - } - return false; -} - -/** @internal */ -export function getResolvePackageJsonImports(compilerOptions: CompilerOptions) { - const moduleResolution = getEmitModuleResolutionKind(compilerOptions); - if (!moduleResolutionSupportsPackageJsonExportsAndImports(moduleResolution)) { - return false; - } - if (compilerOptions.resolvePackageJsonExports !== undefined) { - return compilerOptions.resolvePackageJsonExports; - } - switch (moduleResolution) { - case ModuleResolutionKind.Node16: - case ModuleResolutionKind.NodeNext: - case ModuleResolutionKind.Bundler: - return true; - } - return false; -} - -/** @internal */ -export function getResolveJsonModule(compilerOptions: CompilerOptions) { - if (compilerOptions.resolveJsonModule !== undefined) { - return compilerOptions.resolveJsonModule; - } - return getEmitModuleResolutionKind(compilerOptions) === ModuleResolutionKind.Bundler; -} - -/** @internal */ -export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean { - return !!(compilerOptions.declaration || compilerOptions.composite); -} - -/** @internal */ -export function shouldPreserveConstEnums(compilerOptions: CompilerOptions): boolean { - return !!(compilerOptions.preserveConstEnums || getIsolatedModules(compilerOptions)); -} - -/** @internal */ -export function isIncrementalCompilation(options: CompilerOptions) { - return !!(options.incremental || options.composite); -} - /** @internal */ export type StrictOptionName = | "noImplicitAny" @@ -8787,16 +8820,6 @@ export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: Str return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag]; } -/** @internal */ -export function getAllowJSCompilerOption(compilerOptions: CompilerOptions): boolean { - return compilerOptions.allowJs === undefined ? !!compilerOptions.checkJs : compilerOptions.allowJs; -} - -/** @internal */ -export function getUseDefineForClassFields(compilerOptions: CompilerOptions): boolean { - return compilerOptions.useDefineForClassFields === undefined ? getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022 : compilerOptions.useDefineForClassFields; -} - /** @internal */ export function getEmitStandardClassFields(compilerOptions: CompilerOptions) { return compilerOptions.useDefineForClassFields !== false && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022; diff --git a/tests/baselines/reference/config/showConfig/Show TSConfig with compileOnSave and more/tsconfig.json b/tests/baselines/reference/config/showConfig/Show TSConfig with compileOnSave and more/tsconfig.json index 373e81d1f75f3..b889c35d34086 100644 --- a/tests/baselines/reference/config/showConfig/Show TSConfig with compileOnSave and more/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Show TSConfig with compileOnSave and more/tsconfig.json @@ -3,7 +3,8 @@ "esModuleInterop": true, "target": "es5", "module": "commonjs", - "strict": true + "strict": true, + "allowSyntheticDefaultImports": true }, "references": [ { diff --git a/tests/baselines/reference/config/showConfig/Show TSConfig with paths and more/tsconfig.json b/tests/baselines/reference/config/showConfig/Show TSConfig with paths and more/tsconfig.json index 30bcbb4fdd08b..28b3bd38f3d6c 100644 --- a/tests/baselines/reference/config/showConfig/Show TSConfig with paths and more/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Show TSConfig with paths and more/tsconfig.json @@ -25,7 +25,8 @@ }, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "resolveJsonModule": true + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true }, "include": [ "./src/**/*" diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/checkJs/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/checkJs/tsconfig.json index 21d7a1d2268bf..5e4dbf3f63b2a 100644 --- a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/checkJs/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/checkJs/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { - "checkJs": true + "checkJs": true, + "allowJs": true } } diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/composite/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/composite/tsconfig.json index 664df5f6051d5..67f3febd08537 100644 --- a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/composite/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/composite/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { - "composite": true + "composite": true, + "declaration": true, + "incremental": true } } diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/isolatedModules/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/isolatedModules/tsconfig.json index 78df38c543900..8c42fc0fc0eaa 100644 --- a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/isolatedModules/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/isolatedModules/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { - "isolatedModules": true + "isolatedModules": true, + "preserveConstEnums": true } } diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/module/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/module/tsconfig.json index e7f1c93b4ccb7..6bd841bcf3291 100644 --- a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/module/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/module/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { - "module": "none" + "module": "none", + "moduleResolution": "classic" } } diff --git a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json index 5e2760d642d02..33dd85cb767d5 100644 --- a/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json +++ b/tests/baselines/reference/config/showConfig/Shows tsconfig for single option/verbatimModuleSyntax/tsconfig.json @@ -1,5 +1,7 @@ { "compilerOptions": { - "verbatimModuleSyntax": true + "verbatimModuleSyntax": true, + "isolatedModules": true, + "preserveConstEnums": true } }