Skip to content

Commit da8fc5d

Browse files
authored
Fix 10289: correctly generate tsconfig.json with --lib (#10355)
* Separate generate tsconfig into its own function and implement init with --lib # Conflicts: # src/compiler/tsc.ts * Add tests and baselines; Update function name Add unittests and baselines Add unittests and baselines for generating tsconfig Move unittest into harness folder Update harness tsconfig.json USe correct function name * Use new MapLike interstead. Update unittest # Conflicts: # src/compiler/commandLineParser.ts * Update JakeFile * Add tests for incorrect cases * Address PR : remove explicity write node_modules
1 parent 73a6488 commit da8fc5d

File tree

15 files changed

+229
-68
lines changed

15 files changed

+229
-68
lines changed

Jakefile.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ var harnessSources = harnessCoreSources.concat([
180180
"convertCompilerOptionsFromJson.ts",
181181
"convertTypingOptionsFromJson.ts",
182182
"tsserverProjectSystem.ts",
183-
"matchFiles.ts"
183+
"matchFiles.ts",
184+
"initializeTSConfig.ts",
184185
].map(function (f) {
185186
return path.join(unittestsDirectory, f);
186187
})).concat([

src/compiler/commandLineParser.ts

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,14 @@ namespace ts {
466466
shortOptionNames: Map<string>;
467467
}
468468

469+
/* @internal */
470+
export const defaultInitCompilerOptions: CompilerOptions = {
471+
module: ModuleKind.CommonJS,
472+
target: ScriptTarget.ES5,
473+
noImplicitAny: false,
474+
sourceMap: false,
475+
};
476+
469477
let optionNameMapCache: OptionNameMap;
470478

471479
/* @internal */
@@ -671,6 +679,94 @@ namespace ts {
671679
}
672680
}
673681

682+
/**
683+
* Generate tsconfig configuration when running command line "--init"
684+
* @param options commandlineOptions to be generated into tsconfig.json
685+
* @param fileNames array of filenames to be generated into tsconfig.json
686+
*/
687+
/* @internal */
688+
export function generateTSConfig(options: CompilerOptions, fileNames: string[]): { compilerOptions: Map<CompilerOptionsValue> } {
689+
const compilerOptions = extend(options, defaultInitCompilerOptions);
690+
const configurations: any = {
691+
compilerOptions: serializeCompilerOptions(compilerOptions)
692+
};
693+
if (fileNames && fileNames.length) {
694+
// only set the files property if we have at least one file
695+
configurations.files = fileNames;
696+
}
697+
698+
return configurations;
699+
700+
function getCustomTypeMapOfCommandLineOption(optionDefinition: CommandLineOption): Map<string | number> | undefined {
701+
if (optionDefinition.type === "string" || optionDefinition.type === "number" || optionDefinition.type === "boolean") {
702+
// this is of a type CommandLineOptionOfPrimitiveType
703+
return undefined;
704+
}
705+
else if (optionDefinition.type === "list") {
706+
return getCustomTypeMapOfCommandLineOption((<CommandLineOptionOfListType>optionDefinition).element);
707+
}
708+
else {
709+
return (<CommandLineOptionOfCustomType>optionDefinition).type;
710+
}
711+
}
712+
713+
function getNameOfCompilerOptionValue(value: CompilerOptionsValue, customTypeMap: MapLike<string | number>): string | undefined {
714+
// There is a typeMap associated with this command-line option so use it to map value back to its name
715+
for (const key in customTypeMap) {
716+
if (customTypeMap[key] === value) {
717+
return key;
718+
}
719+
}
720+
return undefined;
721+
}
722+
723+
function serializeCompilerOptions(options: CompilerOptions): Map<CompilerOptionsValue> {
724+
const result = createMap<CompilerOptionsValue>();
725+
const optionsNameMap = getOptionNameMap().optionNameMap;
726+
727+
for (const name in options) {
728+
if (hasProperty(options, name)) {
729+
// tsconfig only options cannot be specified via command line,
730+
// so we can assume that only types that can appear here string | number | boolean
731+
switch (name) {
732+
case "init":
733+
case "watch":
734+
case "version":
735+
case "help":
736+
case "project":
737+
break;
738+
default:
739+
const value = options[name];
740+
let optionDefinition = optionsNameMap[name.toLowerCase()];
741+
if (optionDefinition) {
742+
const customTypeMap = getCustomTypeMapOfCommandLineOption(optionDefinition);
743+
if (!customTypeMap) {
744+
// There is no map associated with this compiler option then use the value as-is
745+
// This is the case if the value is expect to be string, number, boolean or list of string
746+
result[name] = value;
747+
}
748+
else {
749+
if (optionDefinition.type === "list") {
750+
const convertedValue: string[] = [];
751+
for (const element of value as (string | number)[]) {
752+
convertedValue.push(getNameOfCompilerOptionValue(element, customTypeMap));
753+
}
754+
result[name] = convertedValue;
755+
}
756+
else {
757+
// There is a typeMap associated with this command-line option so use it to map value back to its name
758+
result[name] = getNameOfCompilerOptionValue(value, customTypeMap);
759+
}
760+
}
761+
}
762+
break;
763+
}
764+
}
765+
}
766+
return result;
767+
}
768+
}
769+
674770
/**
675771
* Remove the comments from a json like text.
676772
* Comments can be single line comments (starting with # or //) or multiline comments using / * * /

src/compiler/program.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,6 @@ namespace ts {
828828
: { resolvedModule: undefined, failedLookupLocations };
829829
}
830830

831-
/* @internal */
832-
export const defaultInitCompilerOptions: CompilerOptions = {
833-
module: ModuleKind.CommonJS,
834-
target: ScriptTarget.ES5,
835-
noImplicitAny: false,
836-
sourceMap: false,
837-
};
838-
839831
interface OutputFingerprint {
840832
hash: string;
841833
byteOrderMark: boolean;

src/compiler/tsc.ts

Lines changed: 1 addition & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -763,67 +763,11 @@ namespace ts {
763763
reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_tsconfig_json_file_is_already_defined_at_Colon_0, file), /* host */ undefined);
764764
}
765765
else {
766-
const compilerOptions = extend(options, defaultInitCompilerOptions);
767-
const configurations: any = {
768-
compilerOptions: serializeCompilerOptions(compilerOptions)
769-
};
770-
771-
if (fileNames && fileNames.length) {
772-
// only set the files property if we have at least one file
773-
configurations.files = fileNames;
774-
}
775-
else {
776-
configurations.exclude = ["node_modules"];
777-
if (compilerOptions.outDir) {
778-
configurations.exclude.push(compilerOptions.outDir);
779-
}
780-
}
781-
782-
sys.writeFile(file, JSON.stringify(configurations, undefined, 4));
766+
sys.writeFile(file, JSON.stringify(generateTSConfig(options, fileNames), undefined, 4));
783767
reportDiagnostic(createCompilerDiagnostic(Diagnostics.Successfully_created_a_tsconfig_json_file), /* host */ undefined);
784768
}
785769

786770
return;
787-
788-
function serializeCompilerOptions(options: CompilerOptions): Map<string | number | boolean> {
789-
const result = createMap<string | number | boolean>();
790-
const optionsNameMap = getOptionNameMap().optionNameMap;
791-
792-
for (const name in options) {
793-
if (hasProperty(options, name)) {
794-
// tsconfig only options cannot be specified via command line,
795-
// so we can assume that only types that can appear here string | number | boolean
796-
const value = <string | number | boolean>options[name];
797-
switch (name) {
798-
case "init":
799-
case "watch":
800-
case "version":
801-
case "help":
802-
case "project":
803-
break;
804-
default:
805-
let optionDefinition = optionsNameMap[name.toLowerCase()];
806-
if (optionDefinition) {
807-
if (typeof optionDefinition.type === "string") {
808-
// string, number or boolean
809-
result[name] = value;
810-
}
811-
else {
812-
// Enum
813-
const typeMap = <Map<number>>optionDefinition.type;
814-
for (const key in typeMap) {
815-
if (typeMap[key] === value) {
816-
result[name] = key;
817-
}
818-
}
819-
}
820-
}
821-
break;
822-
}
823-
}
824-
}
825-
return result;
826-
}
827771
}
828772
}
829773

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2766,7 +2766,7 @@ namespace ts {
27662766

27672767
/* @internal */
27682768
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
2769-
type: Map<number | string>; // an object literal mapping named values to actual values
2769+
type: Map<number | string>; // an object literal mapping named values to actual values
27702770
}
27712771

27722772
/* @internal */

src/harness/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
"./unittests/convertCompilerOptionsFromJson.ts",
9090
"./unittests/convertTypingOptionsFromJson.ts",
9191
"./unittests/tsserverProjectSystem.ts",
92-
"./unittests/matchFiles.ts"
92+
"./unittests/matchFiles.ts",
93+
"./unittests/initializeTSConfig.ts"
9394
]
9495
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/// <reference path="..\harness.ts" />
2+
/// <reference path="..\..\compiler\commandLineParser.ts" />
3+
4+
namespace ts {
5+
describe("initTSConfig", () => {
6+
function initTSConfigCorrectly(name: string, commandLinesArgs: string[]) {
7+
describe(name, () => {
8+
const commandLine = parseCommandLine(commandLinesArgs);
9+
const initResult = generateTSConfig(commandLine.options, commandLine.fileNames);
10+
const outputFileName = `tsConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;
11+
12+
it(`Correct output for ${outputFileName}`, () => {
13+
Harness.Baseline.runBaseline("Correct output", outputFileName, () => {
14+
if (initResult) {
15+
return JSON.stringify(initResult, undefined, 4);
16+
}
17+
else {
18+
// This can happen if compiler recieve invalid compiler-options
19+
/* tslint:disable:no-null-keyword */
20+
return null;
21+
/* tslint:enable:no-null-keyword */
22+
}
23+
});
24+
});
25+
});
26+
}
27+
28+
initTSConfigCorrectly("Default initialized TSConfig", ["--init"]);
29+
30+
initTSConfigCorrectly("Initialized TSConfig with files options", ["--init", "file0.st", "file1.ts", "file2.ts"]);
31+
32+
initTSConfigCorrectly("Initialized TSConfig with boolean value compiler options", ["--init", "--noUnusedLocals"]);
33+
34+
initTSConfigCorrectly("Initialized TSConfig with enum value compiler options", ["--init", "--target", "es5", "--jsx", "react"]);
35+
36+
initTSConfigCorrectly("Initialized TSConfig with list compiler options", ["--init", "--types", "jquery,mocha"]);
37+
38+
initTSConfigCorrectly("Initialized TSConfig with list compiler options with enum value", ["--init", "--lib", "es5,es2015.core"]);
39+
40+
initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option", ["--init", "--someNonExistOption"]);
41+
42+
initTSConfigCorrectly("Initialized TSConfig with incorrect compiler option value", ["--init", "--lib", "nonExistLib,es5,es2015.promise"]);
43+
});
44+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false,
7+
"noUnusedLocals": true
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false,
7+
"jsx": "react"
8+
}
9+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false
7+
},
8+
"files": [
9+
"file0.st",
10+
"file1.ts",
11+
"file2.ts"
12+
]
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false,
7+
"lib": [
8+
"es5",
9+
"es2015.promise"
10+
]
11+
}
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false
7+
}
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false,
7+
"lib": [
8+
"es5",
9+
"es2015.core"
10+
]
11+
}
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"compilerOptions": {
3+
"module": "commonjs",
4+
"target": "es5",
5+
"noImplicitAny": false,
6+
"sourceMap": false,
7+
"types": [
8+
"jquery",
9+
"mocha"
10+
]
11+
}
12+
}

0 commit comments

Comments
 (0)