Skip to content

Commit 9f19c06

Browse files
authored
Merge pull request #29372 from JoshuaKGoldberg/codefix-enable-decorators
Added codefix to enable experimentalDecorators in the user's config file
2 parents fb99d55 + 7b6adae commit 9f19c06

9 files changed

+159
-11
lines changed

src/compiler/diagnosticMessages.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4811,5 +4811,9 @@
48114811
"Add names to all parameters without names": {
48124812
"category": "Message",
48134813
"code": 95073
4814+
},
4815+
"Enable the 'experimentalDecorators' option in your configuration file": {
4816+
"category": "Message",
4817+
"code": 95074
48144818
}
48154819
}

src/services/codefixes/fixCannotFindModule.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ namespace ts.codefix {
7474
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
7575
if (!tsconfigObjectLiteral) return undefined;
7676

77-
const compilerOptionsProperty = findProperty(tsconfigObjectLiteral, "compilerOptions");
77+
const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions");
7878
if (!compilerOptionsProperty) {
7979
const newCompilerOptions = createObjectLiteral([makeDefaultBaseUrl(), makeDefaultPaths()]);
8080
changes.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment("compilerOptions", newCompilerOptions));
@@ -94,7 +94,7 @@ namespace ts.codefix {
9494
return createJsonPropertyAssignment("baseUrl", createStringLiteral(defaultBaseUrl));
9595
}
9696
function getOrAddBaseUrl(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression): string {
97-
const baseUrlProp = findProperty(compilerOptions, "baseUrl");
97+
const baseUrlProp = findJsonProperty(compilerOptions, "baseUrl");
9898
if (baseUrlProp) {
9999
return isStringLiteral(baseUrlProp.initializer) ? baseUrlProp.initializer.text : defaultBaseUrl;
100100
}
@@ -112,7 +112,7 @@ namespace ts.codefix {
112112
return createJsonPropertyAssignment("paths", createObjectLiteral([makeDefaultPathMapping()]));
113113
}
114114
function getOrAddPathMapping(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression) {
115-
const paths = findProperty(compilerOptions, "paths");
115+
const paths = findJsonProperty(compilerOptions, "paths");
116116
if (!paths || !isObjectLiteralExpression(paths.initializer)) {
117117
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultPaths());
118118
return defaultTypesDirectoryName;
@@ -129,14 +129,6 @@ namespace ts.codefix {
129129
return defaultTypesDirectoryName;
130130
}
131131

132-
function createJsonPropertyAssignment(name: string, initializer: Expression) {
133-
return createPropertyAssignment(createStringLiteral(name), initializer);
134-
}
135-
136-
function findProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
137-
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
138-
}
139-
140132
function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
141133
return { type: "install package", file: fileName, packageName };
142134
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/* @internal */
2+
namespace ts.codefix {
3+
const fixId = "enableExperimentalDecorators";
4+
const errorCodes = [
5+
Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning.code
6+
];
7+
registerCodeFix({
8+
errorCodes,
9+
getCodeActions: (context) => {
10+
const { configFile } = context.program.getCompilerOptions();
11+
if (configFile === undefined) {
12+
return undefined;
13+
}
14+
15+
const changes = textChanges.ChangeTracker.with(context, changeTracker => makeChange(changeTracker, configFile));
16+
return [createCodeFixActionNoFixId(fixId, changes, Diagnostics.Enable_the_experimentalDecorators_option_in_your_configuration_file)];
17+
},
18+
fixIds: [fixId],
19+
});
20+
21+
function makeChange(changeTracker: textChanges.ChangeTracker, configFile: TsConfigSourceFile) {
22+
setJsonCompilerOptionValue(changeTracker, configFile, "experimentalDecorators", createTrue());
23+
}
24+
}

src/services/codefixes/helpers.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,4 +249,46 @@ namespace ts.codefix {
249249
}
250250
return undefined;
251251
}
252+
253+
export function setJsonCompilerOptionValue(
254+
changeTracker: textChanges.ChangeTracker,
255+
configFile: TsConfigSourceFile,
256+
optionName: string,
257+
optionValue: Expression,
258+
) {
259+
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
260+
if (!tsconfigObjectLiteral) return undefined;
261+
262+
const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions");
263+
if (compilerOptionsProperty === undefined) {
264+
changeTracker.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment(
265+
"compilerOptions",
266+
createObjectLiteral([
267+
createJsonPropertyAssignment(optionName, optionValue),
268+
])));
269+
return;
270+
}
271+
272+
const compilerOptions = compilerOptionsProperty.initializer;
273+
if (!isObjectLiteralExpression(compilerOptions)) {
274+
return;
275+
}
276+
277+
const optionProperty = findJsonProperty(compilerOptions, optionName);
278+
279+
if (optionProperty === undefined) {
280+
changeTracker.insertNodeAtObjectStart(configFile, compilerOptions, createJsonPropertyAssignment(optionName, optionValue));
281+
}
282+
else {
283+
changeTracker.replaceNode(configFile, optionProperty.initializer, optionValue);
284+
}
285+
}
286+
287+
export function createJsonPropertyAssignment(name: string, initializer: Expression) {
288+
return createPropertyAssignment(createStringLiteral(name), initializer);
289+
}
290+
291+
export function findJsonProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
292+
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
293+
}
252294
}

src/services/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
6262
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
6363
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
64+
"codefixes/fixEnableExperimentalDecorators.ts",
6465
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
6566
"codefixes/fixForgottenThisPropertyAccess.ts",
6667
"codefixes/fixUnusedIdentifier.ts",
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /dir/a.ts
4+
////declare const decorator: any;
5+
////class A {
6+
//// @decorator method() {};
7+
////};
8+
9+
// @Filename: /dir/tsconfig.json
10+
////{
11+
//// "compilerOptions": {
12+
//// }
13+
////}
14+
15+
goTo.file("/dir/a.ts");
16+
verify.codeFix({
17+
description: "Enable the 'experimentalDecorators' option in your configuration file",
18+
newFileContent: {
19+
"/dir/tsconfig.json":
20+
`{
21+
"compilerOptions": {
22+
"experimentalDecorators": true,
23+
}
24+
}`,
25+
},
26+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /dir/a.ts
4+
////declare const decorator: any;
5+
////class A {
6+
//// @decorator method() {};
7+
////};
8+
9+
// @Filename: /dir/tsconfig.json
10+
////{
11+
//// "compilerOptions": {
12+
//// "experimentalDecorators": false,
13+
//// }
14+
////}
15+
16+
goTo.file("/dir/a.ts");
17+
verify.codeFix({
18+
description: "Enable the 'experimentalDecorators' option in your configuration file",
19+
newFileContent: {
20+
"/dir/tsconfig.json":
21+
`{
22+
"compilerOptions": {
23+
"experimentalDecorators": true,
24+
}
25+
}`,
26+
},
27+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /dir/a.ts
4+
////declare const decorator: any;
5+
////class A {
6+
//// @decorator method() {};
7+
////};
8+
9+
// @Filename: /dir/tsconfig.json
10+
////{
11+
////}
12+
13+
goTo.file("/dir/a.ts");
14+
verify.codeFix({
15+
description: "Enable the 'experimentalDecorators' option in your configuration file",
16+
newFileContent: {
17+
"/dir/tsconfig.json":
18+
`{
19+
"compilerOptions": { "experimentalDecorators": true },
20+
}`,
21+
},
22+
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @Filename: /dir/a.ts
4+
////declare const decorator: any;
5+
////class A {
6+
//// @decorator method() {};
7+
////};
8+
9+
goTo.file("/dir/a.ts");
10+
verify.not.codeFixAvailable();

0 commit comments

Comments
 (0)