diff --git a/src/autofix/solutions/codeReplacer.ts b/src/autofix/solutions/codeReplacer.ts index 9f62d9e9f..96fbce7da 100644 --- a/src/autofix/solutions/codeReplacer.ts +++ b/src/autofix/solutions/codeReplacer.ts @@ -314,6 +314,12 @@ function patchMessageFixHints(fixHints?: FixHints, apiName?: string) { `$moduleIdentifier.${fnName}(${cleanRedundantArguments(fixHints.exportCodeToBeUsed.args)})`; } } + } else if (apiName === "applyTheme" && fixHints?.moduleName === "sap/ui/core/Theming") { + if ((fixHints?.exportCodeToBeUsed?.args?.length ?? 0) > 1 && + fixHints?.exportCodeToBeUsed?.args?.[1]?.value !== "undefined") { + fixHints = undefined; // We cannot handle this case + log.verbose(`Autofix skipped for ${apiName}. Transpilation is too ambiguous.`); + } } return fixHints; diff --git a/src/linter/ui5Types/fixHints/CoreFixHintsGenerator.ts b/src/linter/ui5Types/fixHints/CoreFixHintsGenerator.ts index b3934f9f6..3c1accdb4 100644 --- a/src/linter/ui5Types/fixHints/CoreFixHintsGenerator.ts +++ b/src/linter/ui5Types/fixHints/CoreFixHintsGenerator.ts @@ -39,21 +39,21 @@ const coreModulesReplacements = new Map([ ["byFieldGroupId", { moduleName: "sap/ui/core/Control", exportCodeToBeUsed: "$moduleIdentifier.getControlsByFieldGroupId($1)", }], + ["getCurrentFocusedControlId", { + // The legacy API used to return null if no control was focused. + moduleName: "sap/ui/core/Element", exportCodeToBeUsed: "$moduleIdentifier.getActiveElement()?.getId() || null", + }], ["isStaticAreaRef", { moduleName: "sap/ui/core/StaticArea", exportCodeToBeUsed: "$moduleIdentifier.getDomRef() === $1", }], - // TODO: The legacy API return null if the control is not found. - // ["getCurrentFocusedControlId", { - // moduleName: "sap/ui/core/Element", exportNameToBeUsed: "getActiveElement()?.getId", - // }], - // // Migrate only if second argument is omitted or undefined - // ["applyTheme", { - // moduleName: "sap/ui/core/Theming", - // exportCodeToBeUsed: "$moduleIdentifier.setTheme($1)", - // }], - // // Individual arguments must be mapped to "options" object - // // The new API has no sync loading option, replacement is only safe when the options contain async:true + // Migrate only if second argument is omitted or undefined + ["applyTheme", { + moduleName: "sap/ui/core/Theming", + exportCodeToBeUsed: "$moduleIdentifier.setTheme($1)", + }], + // Individual arguments must be mapped to "options" object + // The new API has no sync loading option, replacement is only safe when the options contain async:true // ["loadLibrary", { // moduleName: "sap/ui/core/Lib", exportCodeToBeUsed: "$moduleIdentifier.load($1)", // }], @@ -63,14 +63,14 @@ const coreModulesReplacements = new Map([ // ["createComponent", { // moduleName: "sap/ui/core/Component", exportCodeToBeUsed: "$moduleIdentifier.create($1)", // }], - // // Note that alternative replacement Component.get is meanwhile deprecated, too - // ["getComponent", { - // moduleName: "sap/ui/core/Component", exportNameToBeUsed: "getComponentById", - // }], - // // Parameter bAsync has to be omitted or set to false since the new API returns - // // the resource bundle synchronously. When bAsync is true, the new API is not a replacement - // // as it does not return a promise. In an await expression, it would be okay, but otherwise not. - // // TODO: To be discussed: sLibrary must be a library, that might not be easy to check + // Note that alternative replacement Component.get is meanwhile deprecated, too + ["getComponent", { + moduleName: "sap/ui/core/Component", exportNameToBeUsed: "getComponentById", + }], + // Parameter bAsync has to be omitted or set to false since the new API returns + // the resource bundle synchronously. When bAsync is true, the new API is not a replacement + // as it does not return a promise. In an await expression, it would be okay, but otherwise not. + // TODO: To be discussed: sLibrary must be a library, that might not be easy to check // ["getLibraryResourceBundle", { // moduleName: "sap/ui/core/Lib", exportCodeToBeUsed: "$moduleIdentifier.getResourceBundleFor($1, $2)", // }], diff --git a/test/fixtures/autofix/coreApi/DeprecatedCoreApi.js b/test/fixtures/autofix/coreApi/DeprecatedCoreApi.js index 1fd45bdd3..e196e7d56 100644 --- a/test/fixtures/autofix/coreApi/DeprecatedCoreApi.js +++ b/test/fixtures/autofix/coreApi/DeprecatedCoreApi.js @@ -1,4 +1,8 @@ sap.ui.define(["sap/ui/core/Core",], function(CoreRenamed) { + CoreRenamed.applyTheme("themeName"); + CoreRenamed.applyTheme("customTheme", "find/my/theme/here"); // Should not be autofixed if there is a 2nd argument + CoreRenamed.applyTheme("customTheme", undefined); // Can be migrated when the 2nd argument is undefined + CoreRenamed.attachInit(function() {console.log();}); CoreRenamed.attachInitEvent(function() {console.log();}); @@ -8,8 +12,12 @@ sap.ui.define(["sap/ui/core/Core",], function(CoreRenamed) { CoreRenamed.byId("id"); + CoreRenamed.getComponent("componentId"); + CoreRenamed.getControl("controlId"); + CoreRenamed.getCurrentFocusedControlId(); + CoreRenamed.getElementById("elementId"); CoreRenamed.getEventBus(); diff --git a/test/fixtures/autofix/coreApi/DeprecatedCoreApiWithoutImport.js b/test/fixtures/autofix/coreApi/DeprecatedCoreApiWithoutImport.js index bfb2aa5cc..e1f3e408c 100644 --- a/test/fixtures/autofix/coreApi/DeprecatedCoreApiWithoutImport.js +++ b/test/fixtures/autofix/coreApi/DeprecatedCoreApiWithoutImport.js @@ -1,7 +1,10 @@ sap.ui.define([], function() { const globalCore = sap.ui.getCore(); - - globalCore.attachInit(function() {console.log();}); + + sap.ui.getCore().applyTheme("themeName"); + sap.ui.getCore().applyTheme("customTheme", "find/my/theme/here"); // Should not be autofixed if there is a 2nd argument + sap.ui.getCore().applyTheme("customTheme", undefined); // Can be autofixed when the 2nd argument is undefined + sap.ui.getCore().attachInit(function() {console.log();}); globalCore.attachInitEvent(function() {console.log();}); @@ -13,10 +16,14 @@ sap.ui.define([], function() { globalCore.byId("id"); sap.ui.getCore().byId("id"); - globalCore.getControl("controlId"); + globalCore.getComponent("componentId"); + sap.ui.getCore().getComponent("componentId"); + sap.ui.getCore().getControl("controlId"); - globalCore.getElementById("elementId"); + globalCore.getCurrentFocusedControlId(); + sap.ui.getCore().getCurrentFocusedControlId(); + sap.ui.getCore().getElementById("elementId"); globalCore.getEventBus(); diff --git a/test/lib/autofix/snapshots/autofix.fixtures.ts.md b/test/lib/autofix/snapshots/autofix.fixtures.ts.md index 3f2b0cac0..ccd2b786a 100644 --- a/test/lib/autofix/snapshots/autofix.fixtures.ts.md +++ b/test/lib/autofix/snapshots/autofix.fixtures.ts.md @@ -5213,7 +5213,12 @@ Generated by [AVA](https://avajs.dev). > AutofixResult: /coreApi/DeprecatedCoreApi.js - `sap.ui.define(["sap/ui/core/Core", "sap/ui/core/Control", "sap/ui/core/Element", "sap/ui/core/EventBus", "sap/ui/core/Lib", "sap/ui/core/StaticArea", "sap/ui/core/Theming", "sap/ui/Device",], function(CoreRenamed, Control, Element, EventBus, Lib, StaticArea, Theming, Device) {␊ + `sap.ui.define(["sap/ui/core/Core", "sap/ui/core/Component", "sap/ui/core/Control", "sap/ui/core/Element", "sap/ui/core/EventBus", "sap/ui/core/Lib", "sap/ui/core/StaticArea", "sap/ui/core/Theming",␊ + "sap/ui/Device",], function(CoreRenamed, Component, Control, Element, EventBus, Lib, StaticArea, Theming, Device) {␊ + Theming.setTheme("themeName");␊ + CoreRenamed.applyTheme("customTheme", "find/my/theme/here"); // Should not be autofixed if there is a 2nd argument␊ + Theming.setTheme("customTheme"); // Can be migrated when the 2nd argument is undefined␊ + ␊ CoreRenamed.ready(function() {console.log();});␊ ␊ CoreRenamed.ready(function() {console.log();});␊ @@ -5222,8 +5227,12 @@ Generated by [AVA](https://avajs.dev). Control.getControlsByFieldGroupId(["id", "id2"]);␊ ␊ Element.getElementById("id");␊ + ␊ + Component.getComponentById("componentId");␊ ␊ Element.getElementById("controlId");␊ + ␊ + Element.getActiveElement()?.getId() || null;␊ ␊ Element.getElementById("elementId");␊ ␊ @@ -5258,13 +5267,21 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 1, + errorCount: 2, fatalErrorCount: 0, filePath: 'DeprecatedCoreApi.js', messages: [ + { + column: 14, + line: 4, + message: 'Call to deprecated function \'applyTheme\' of class \'Core\'', + messageDetails: 'Deprecated test message', + ruleId: 'no-deprecated-api', + severity: 2, + }, { column: 2, - line: 19, + line: 28, message: 'Deprecated call to Lib.init(). Use the {apiVersion: 2} parameter instead', messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', ruleId: 'no-deprecated-api', @@ -5279,9 +5296,14 @@ Generated by [AVA](https://avajs.dev). > AutofixResult: /coreApi/DeprecatedCoreApiWithoutImport.js - `sap.ui.define(["sap/ui/core/Control", "sap/ui/core/Core", "sap/ui/core/Element", "sap/ui/core/EventBus", "sap/ui/core/Lib", "sap/ui/core/StaticArea", "sap/ui/core/Theming", "sap/ui/Device"], function(Control, Core, Element, EventBus, Lib, StaticArea, Theming, Device) {␊ + `sap.ui.define(["sap/ui/core/Component", "sap/ui/core/Control", "sap/ui/core/Core", "sap/ui/core/Element", "sap/ui/core/EventBus", "sap/ui/core/Lib", "sap/ui/core/StaticArea", "sap/ui/core/Theming",␊ + "sap/ui/Device"], function(Component, Control, Core, Element, EventBus, Lib, StaticArea, Theming, Device) {␊ const globalCore = sap.ui.getCore();␊ - ␊ + ␊ + Theming.setTheme("themeName");␊ + sap.ui.getCore().applyTheme("customTheme", "find/my/theme/here"); // Should not be autofixed if there is a 2nd argument␊ + Theming.setTheme("customTheme"); // Can be autofixed when the 2nd argument is undefined␊ + ␊ Core.ready(function() {console.log();});␊ Core.ready(function() {console.log();});␊ ␊ @@ -5293,9 +5315,14 @@ Generated by [AVA](https://avajs.dev). ␊ Element.getElementById("id");␊ Element.getElementById("id");␊ + ␊ + Component.getComponentById("componentId");␊ + Component.getComponentById("componentId");␊ ␊ Element.getElementById("controlId");␊ - Element.getElementById("controlId");␊ + ␊ + Element.getActiveElement()?.getId() || null;␊ + Element.getActiveElement()?.getId() || null;␊ ␊ Element.getElementById("elementId");␊ Element.getElementById("elementId");␊ @@ -5336,13 +5363,13 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 3, + errorCount: 6, fatalErrorCount: 0, filePath: 'DeprecatedCoreApiWithoutImport.js', messages: [ { column: 21, - line: 2, + line: 3, message: 'Access of global variable \'sap\' (sap.ui.getCore)', messageDetails: 'Do not use global variables to access UI5 modules or APIs. See Best Practices for Developers (https://ui5.sap.com/#/topic/28fcd55b04654977b63dacbee0552712)', ruleId: 'no-globals', @@ -5350,7 +5377,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 28, - line: 2, + line: 3, message: 'Call to deprecated function \'getCore\' (sap.ui.getCore)', messageDetails: 'Deprecated test message', ruleId: 'no-deprecated-api', @@ -5358,7 +5385,31 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 28, + line: 6, + message: 'Access of global variable \'sap\' (sap.ui.getCore)', + messageDetails: 'Do not use global variables to access UI5 modules or APIs. See Best Practices for Developers (https://ui5.sap.com/#/topic/28fcd55b04654977b63dacbee0552712)', + ruleId: 'no-globals', + severity: 2, + }, + { + column: 9, + line: 6, + message: 'Call to deprecated function \'getCore\' (sap.ui.getCore)', + messageDetails: 'Deprecated test message', + ruleId: 'no-deprecated-api', + severity: 2, + }, + { + column: 19, + line: 6, + message: 'Call to deprecated function \'applyTheme\' of class \'Core\'', + messageDetails: 'Deprecated test message', + ruleId: 'no-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 36, message: 'Deprecated call to Lib.init(). Use the {apiVersion: 2} parameter instead', messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', ruleId: 'no-deprecated-api', diff --git a/test/lib/autofix/snapshots/autofix.fixtures.ts.snap b/test/lib/autofix/snapshots/autofix.fixtures.ts.snap index e1534e872..87f16e1d3 100644 Binary files a/test/lib/autofix/snapshots/autofix.fixtures.ts.snap and b/test/lib/autofix/snapshots/autofix.fixtures.ts.snap differ