From ba61f1534c5aa7bd367b97afe553feb1e527425d Mon Sep 17 00:00:00 2001 From: Matthias Osswald Date: Fri, 2 Aug 2024 10:48:59 +0200 Subject: [PATCH 01/12] feat: Detect deprecated usage of Parameters.get API --- src/linter/ui5Types/SourceFileLinter.ts | 34 ++++++++++++++++++ .../NoDeprecatedApi/PartialDeprecation.js | 12 +++++-- .../rules/snapshots/NoDeprecatedApi.ts.md | 13 +++++-- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 9430 -> 9526 bytes 4 files changed, 53 insertions(+), 6 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 6cd520ef3..4df119d9b 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -89,6 +89,8 @@ export default class SourceFileLinter { this.analyzePropertyAccessExpression(node as ts.CallExpression); // Check for global this.analyzeCallExpression(node as ts.CallExpression); // Check for deprecation this.analyzeLibInitCall(node as ts.CallExpression); // Check for sap/ui/core/Lib.init usages + // Check for sap/ui/core/theming/Parameters.get usages + this.analyzeParametersGetCall(node as ts.CallExpression); } else if (node.kind === ts.SyntaxKind.PropertyAccessExpression || node.kind === ts.SyntaxKind.ElementAccessExpression) { this.analyzePropertyAccessExpression( @@ -438,6 +440,38 @@ export default class SourceFileLinter { }); } + analyzeParametersGetCall(node: ts.CallExpression) { + if (!ts.isIdentifier(node.expression) && + !ts.isPropertyAccessExpression(node.expression) && + !ts.isElementAccessExpression(node.expression)) { + return; + } + + const nodeExp = node.expression; + const nodeType = this.#checker.getTypeAtLocation(nodeExp); + if (!nodeType.symbol || nodeType.symbol.getName() !== "get") { + return; + } + + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/theming/Parameters") { + return; + } + + if (node.arguments.length && ts.isObjectLiteralExpression(node.arguments[0])) { + // Non-deprecated usage + return; + } + + this.#reporter.addMessage({ + node, + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + message: "Usage of deprecated variant of 'sap/ui/core/theming/Parameters.get'", + messageDetails: this.#messageDetails ? "" : undefined, + }); + } + getDeprecationInfoForAccess(node: ts.AccessExpression): DeprecationInfo | null { let symbol; if (ts.isPropertyAccessExpression(node)) { diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index 3074762ab..f5eb26113 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -5,9 +5,15 @@ sap.ui.define([ "sap/ui/model/odata/v2/ODataModel" ], function(Parameters, JSONModel, ODataModelV4, ODataModelV2) { - Parameters.get(); // TODO detect: (deprecated since 1.92) If no parameter is given - Parameters.get("sapUiParam1"); // TODO detect: (deprecated since 1.94) If a string is given as first parameter - Parameters.get(["sapUiParam1", "sapUiParam2"]); // TODO detect: (deprecated since 1.94) If an array is given as first parameter + Parameters.get(); // (deprecated since 1.92) If no parameter is given + Parameters.get("sapUiParam1"); // (deprecated since 1.94) If a string is given as first parameter + Parameters.get(["sapUiParam1", "sapUiParam2"]); // (deprecated since 1.94) If an array is given as first parameter + + // Negative test: Passing an object is the only non-deprecated usage + Parameters.get({ + name: ["sapUiParam1", "sapUiParam2", "sapUiParam3"], + callback: function(mParams) {} + }); var jsonModel = new JSONModel(); jsonModel.loadData("/api/users", undefined, false); // TODO detect: Parameter bAsync is deprecated as of Version 1.107 (default=true) diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index aeaa82754..131ace939 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -442,10 +442,17 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, + errorCount: 1, + fatalErrorCount: 1, filePath: 'PartialDeprecation.js', - messages: [], + messages: [ + { + fatal: true, + message: 'Invalid arguments: Missing second argument', + ruleId: 'ui5-linter-parsing-error', + severity: 2, + }, + ], warningCount: 0, }, ] diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index b46b6090a2bfdbbc06b2759e558de50fbae181c8..d6d54f408032a6668785ca19aa0d03afdb6320e5 100644 GIT binary patch literal 9526 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 SQ}IV%FcZFgmMx@1M*2U;D`i*! literal 9430 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 Date: Wed, 21 Aug 2024 14:59:52 +0200 Subject: [PATCH 02/12] test: Extend fixture --- .../linter/rules/NoDeprecatedApi/PartialDeprecation.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index f5eb26113..c9e251ba8 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -15,6 +15,9 @@ sap.ui.define([ callback: function(mParams) {} }); + var getParam = Parameters.get; + getParam(); // (deprecated since 1.92) If no parameter is given + var jsonModel = new JSONModel(); jsonModel.loadData("/api/users", undefined, false); // TODO detect: Parameter bAsync is deprecated as of Version 1.107 (default=true) From 7fb4bac3b9533db4b275f73a67e713dcfb93e83d Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 6 Sep 2024 16:35:49 +0200 Subject: [PATCH 03/12] feat: Detect Component#createComponent partial deprecation --- src/linter/ui5Types/SourceFileLinter.ts | 48 +++++++++++++++++++ .../NoDeprecatedApi/PartialDeprecation.js | 26 +++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 4df119d9b..29b063805 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -91,6 +91,7 @@ export default class SourceFileLinter { this.analyzeLibInitCall(node as ts.CallExpression); // Check for sap/ui/core/Lib.init usages // Check for sap/ui/core/theming/Parameters.get usages this.analyzeParametersGetCall(node as ts.CallExpression); + this.analyzeCreateComponentCall(node as ts.CallExpression); } else if (node.kind === ts.SyntaxKind.PropertyAccessExpression || node.kind === ts.SyntaxKind.ElementAccessExpression) { this.analyzePropertyAccessExpression( @@ -472,6 +473,53 @@ export default class SourceFileLinter { }); } + analyzeCreateComponentCall(node: ts.CallExpression) { + if (!ts.isIdentifier(node.expression) && + !ts.isPropertyAccessExpression(node.expression) && + !ts.isElementAccessExpression(node.expression)) { + return; + } + + const nodeExp = node.expression; + const nodeType = this.#checker.getTypeAtLocation(nodeExp); + if (!nodeType.symbol || nodeType.symbol.getName() !== "createComponent") { + return; + } + + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/Component") { + return; + } + + if (!node.arguments.length || !ts.isObjectLiteralExpression(node.arguments[0])) { + return; + } + const firstArg = node.arguments[0]; + let asyncFalseFound = false; + for (const prop of firstArg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + if (prop.name.getText() !== "async") { + continue; + } + if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { + asyncFalseFound = true; + break; + } + } + + if (asyncFalseFound) { + this.#reporter.addMessage({ + node, + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + message: "Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component.createComponent'", + messageDetails: this.#messageDetails ? "" : undefined, + }); + } + } + getDeprecationInfoForAccess(node: ts.AccessExpression): DeprecationInfo | null { let symbol; if (ts.isPropertyAccessExpression(node)) { diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index c9e251ba8..0eefe6cdb 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -3,7 +3,8 @@ sap.ui.define([ "sap/ui/model/json/JSONModel", "sap/ui/model/odata/v4/ODataModel", "sap/ui/model/odata/v2/ODataModel" -], function(Parameters, JSONModel, ODataModelV4, ODataModelV2) { + "sap/ui/core/Component" +], function(Parameters, JSONModel, ODataModelV4, ODataModelV2, Component) { Parameters.get(); // (deprecated since 1.92) If no parameter is given Parameters.get("sapUiParam1"); // (deprecated since 1.94) If a string is given as first parameter @@ -31,4 +32,27 @@ sap.ui.define([ properties: ["property1", "property2"] // TODO detect: Passing a list of property names is deprecated since 1.120; pass the initial values as an object instead }); + Component.create({ + name: "my.comp", + url: "find/my/comp/here", + id: "myCompId1" + }).then(function(oComponent) { + oComponent.createComponent({ + usage: "myUsage", + id: "myId", + async: false, // Deprecated: "async" must be true or omitted + }); + // Negative test: No async flag will default to true + oComponent.createComponent({ + usage: "myUsage", + id: "myId", + }); + // Negative test: async true is correct + oComponent.createComponent({ + usage: "myUsage", + id: "myId", + async: true, + }); + }); + }); From 370646ebf68f48db141fa1925c8549207b68d00d Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 6 Sep 2024 17:33:14 +0200 Subject: [PATCH 04/12] feat: Detect v2/OdataModel#loadData and v4 #createEntry partial deprecation --- src/linter/ui5Types/SourceFileLinter.ts | 112 +++++++++++++++++- .../NoDeprecatedApi/PartialDeprecation.js | 1 + 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 29b063805..8f8460b00 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -92,6 +92,8 @@ export default class SourceFileLinter { // Check for sap/ui/core/theming/Parameters.get usages this.analyzeParametersGetCall(node as ts.CallExpression); this.analyzeCreateComponentCall(node as ts.CallExpression); + this.analyzeJsonModelLoadDataCall(node as ts.CallExpression); + this.analyzeOdataModelV2CreateEntry(node as ts.CallExpression); } else if (node.kind === ts.SyntaxKind.PropertyAccessExpression || node.kind === ts.SyntaxKind.ElementAccessExpression) { this.analyzePropertyAccessExpression( @@ -495,7 +497,7 @@ export default class SourceFileLinter { return; } const firstArg = node.arguments[0]; - let asyncFalseFound = false; + let asyncFalseNode; for (const prop of firstArg.properties) { if (!ts.isPropertyAssignment(prop)) { continue; @@ -504,18 +506,116 @@ export default class SourceFileLinter { continue; } if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { - asyncFalseFound = true; + asyncFalseNode = prop; break; } } - if (asyncFalseFound) { + if (asyncFalseNode) { this.#reporter.addMessage({ - node, + node: asyncFalseNode, + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + message: "Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component#createComponent'", + messageDetails: this.#messageDetails ? + "Property 'async' must be either omitted or set to true" : + undefined, + }); + } + } + + analyzeOdataModelV2CreateEntry(node: ts.CallExpression) { + if (!ts.isIdentifier(node.expression) && + !ts.isPropertyAccessExpression(node.expression) && + !ts.isElementAccessExpression(node.expression)) { + return; + } + + const nodeExp = node.expression; + const nodeType = this.#checker.getTypeAtLocation(nodeExp); + if (!nodeType.symbol || nodeType.symbol.getName() !== "createEntry") { + return; + } + + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/model/odata/v2/ODataModel") { + return; + } + + if (!node.arguments.length || node.arguments.length < 2 || !ts.isObjectLiteralExpression(node.arguments[1])) { + return; + } + const secondArg = node.arguments[1]; + let batchGroupId; + for (const prop of secondArg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + if (prop.name.getText() === "batchGroupId") { + batchGroupId = prop; + } + } + + if (batchGroupId) { + this.#reporter.addMessage({ + node: batchGroupId, + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + message: + "Usage of deprecated parameter 'batchGroupId' in 'sap/ui/model/odata/v2/ODataModel#createEntry'", + messageDetails: this.#messageDetails ? "Use parameter 'groupId' instead" : undefined, + }); + } + } + + analyzeJsonModelLoadDataCall(node: ts.CallExpression) { + if (!ts.isIdentifier(node.expression) && + !ts.isPropertyAccessExpression(node.expression) && + !ts.isElementAccessExpression(node.expression)) { + return; + } + + const nodeExp = node.expression; + const nodeType = this.#checker.getTypeAtLocation(nodeExp); + if (!nodeType.symbol || nodeType.symbol.getName() !== "loadData") { + return; + } + + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/model/json/JSONModel") { + return; + } + + if (!node.arguments.length || node.arguments.length < 2) { + return; + } + + const asyncArg = node.arguments[2]; + if (asyncArg.kind === ts.SyntaxKind.FalseKeyword) { + this.#reporter.addMessage({ + node: asyncArg, + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + message: "Usage of deprecated value for parameter 'bAsync' of 'sap/ui/model/json/JSONModel#loadData'", + messageDetails: this.#messageDetails ? + "Parameter 'bAsync' must be either omitted or set to true" : + undefined, + }); + } + + if (node.arguments.length < 5) { + return; + } + const cacheArg = node.arguments[5]; + if (cacheArg.kind === ts.SyntaxKind.FalseKeyword) { + this.#reporter.addMessage({ + node: cacheArg, severity: LintMessageSeverity.Error, ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: "Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component.createComponent'", - messageDetails: this.#messageDetails ? "" : undefined, + message: "Usage of deprecated value for parameter 'bCache' of 'sap/ui/model/json/JSONModel#loadData'", + messageDetails: this.#messageDetails ? + "Parameter 'bCache' must be either omitted or set to true" : + undefined, }); } } diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index 0eefe6cdb..07039c74e 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -21,6 +21,7 @@ sap.ui.define([ var jsonModel = new JSONModel(); jsonModel.loadData("/api/users", undefined, false); // TODO detect: Parameter bAsync is deprecated as of Version 1.107 (default=true) + jsonModel.loadData("/api/users", undefined, true, "GET", false, false); // TODO detect: Parameter bCache is deprecated as of Version 1.107 (default=true) var v4Model = new ODataModelV4({ synchronizationMode: "None" // TODO detect: Parameter "synchronizationMode" is deprecated since 1.110 From 55ec3143e81a4ff5d06c8b4c7c7973055303722a Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 9 Sep 2024 11:11:34 +0200 Subject: [PATCH 05/12] refactor: Use new #addMessage signature, check new Router --- src/linter/messages.ts | 56 ++++++ src/linter/ui5Types/SourceFileLinter.ts | 162 +++++++----------- .../NoDeprecatedApi/PartialDeprecation.js | 7 +- .../rules/snapshots/NoDeprecatedApi.ts.md | 84 ++++++++- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 9526 -> 10196 bytes 5 files changed, 202 insertions(+), 107 deletions(-) diff --git a/src/linter/messages.ts b/src/linter/messages.ts index d0e99e2de..70bf6d98a 100644 --- a/src/linter/messages.ts +++ b/src/linter/messages.ts @@ -15,6 +15,11 @@ export enum MESSAGE { NO_DIRECT_DATATYPE_ACCESS, NO_DIRECT_ENUM_ACCESS, NO_GLOBALS, + PARTIALLY_DEPRECATED_PARAMETERS_GET, + PARTIALLY_DEPRECATED_CREATE_COMPONENT, + PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY, + PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA, + PARTIALLY_DEPRECATED_CORE_ROUTER, } export const MESSAGE_INFO = { @@ -145,4 +150,55 @@ export const MESSAGE_INFO = { details: () => undefined, }, + [MESSAGE.PARTIALLY_DEPRECATED_PARAMETERS_GET]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated variant of 'sap/ui/core/theming/Parameters.get'`, + details: () => `{@link sap.ui.core.theming.Parameters#sap.ui.core.theming.Parameters.get Parameters.get}`, + }, + + [MESSAGE.PARTIALLY_DEPRECATED_CREATE_COMPONENT]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component#createComponent'`, + details: () => `Property 'async' must be either omitted or set to true. ` + + `{@link sap.ui.core.Component#createComponent See API reference}`, + }, + + [MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated parameter 'batchGroupId' in 'sap/ui/model/odata/v2/ODataModel#createEntry'`, + details: () => `Use parameter 'groupId' instead. ` + + `{@link sap.ui.model.odata.v2.ODataModel#createEntry See API reference}`, + }, + + [MESSAGE.PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: ({paramName}: {paramName: string}) => + `Usage of deprecated value for parameter '${paramName}' of 'sap/ui/model/json/JSONModel#loadData'`, + details: ({paramName}: {paramName: string}) => + `Parameter '${paramName}' must be either omitted or set to true. ` + + `{@link sap.ui.model.json.JSONModel#loadData See API reference}`, + }, + + [MESSAGE.PARTIALLY_DEPRECATED_CORE_ROUTER]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated value for parameter 'oConfig.async' of constructor of 'sap/ui/core/Router'`, + details: () => + `Parameter 'oConfig.async' must be set to true. ` + + `{@link sap/ui/core/routing/Router#constructor See API reference}`, + }, + } as const; diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 8f8460b00..da2c82923 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -80,20 +80,11 @@ export default class SourceFileLinter { visitNode(node: ts.Node) { if (node.kind === ts.SyntaxKind.NewExpression) { // e.g. "new Button({\n\t\t\t\tblocked: true\n\t\t\t})" - const nodeType = this.#checker.getTypeAtLocation(node); // checker.getContextualType(node); - if (nodeType.symbol && this.isSymbolOfUi5OrThirdPartyType(nodeType.symbol)) { - this.analyzeNewExpression(nodeType, node as ts.NewExpression); - } + this.analyzeNewExpression(node as ts.NewExpression); } else if (node.kind === ts.SyntaxKind.CallExpression) { // ts.isCallLikeExpression too? // const nodeType = this.#checker.getTypeAtLocation(node); this.analyzePropertyAccessExpression(node as ts.CallExpression); // Check for global this.analyzeCallExpression(node as ts.CallExpression); // Check for deprecation - this.analyzeLibInitCall(node as ts.CallExpression); // Check for sap/ui/core/Lib.init usages - // Check for sap/ui/core/theming/Parameters.get usages - this.analyzeParametersGetCall(node as ts.CallExpression); - this.analyzeCreateComponentCall(node as ts.CallExpression); - this.analyzeJsonModelLoadDataCall(node as ts.CallExpression); - this.analyzeOdataModelV2CreateEntry(node as ts.CallExpression); } else if (node.kind === ts.SyntaxKind.PropertyAccessExpression || node.kind === ts.SyntaxKind.ElementAccessExpression) { this.analyzePropertyAccessExpression( @@ -182,9 +173,15 @@ export default class SourceFileLinter { }); } - analyzeNewExpression(nodeType: ts.Type, node: ts.NewExpression) { + analyzeNewExpression(node: ts.NewExpression) { + const nodeType = this.#checker.getTypeAtLocation(node); // checker.getContextualType(node); + if (!nodeType.symbol || !this.isSymbolOfUi5OrThirdPartyType(nodeType.symbol)) { + return; + } const classType = this.#checker.getTypeAtLocation(node.expression); + this.analyzeNewCoreRouter(node, classType); + // There can be multiple and we need to find the right one const [constructSignature] = classType.getConstructSignatures(); @@ -283,14 +280,21 @@ export default class SourceFileLinter { return; } - if (!ts.isPropertyAccessExpression(exprNode) && - !ts.isElementAccessExpression(exprNode) && - !ts.isIdentifier(exprNode) && + if (!ts.isPropertyAccessExpression(exprNode) && // Lib.init() + !ts.isElementAccessExpression(exprNode) && // Lib["init"]() + !ts.isIdentifier(exprNode) && // Assignment `const LibInit = Library.init` and destructuring !ts.isCallExpression(exprNode)) { // TODO: Transform into coverage message if it's really ok not to handle this throw new Error(`Unhandled CallExpression expression syntax: ${ts.SyntaxKind[exprNode.kind]}`); } + this.#analyzeLibInitCall(node, exprType); // Check for sap/ui/core/Lib.init usages + // Check for partially deprecated calls + this.#analyzeParametersGetCall(node, exprType); + this.#analyzeCreateComponentCall(node, exprType); + this.#analyzeJsonModelLoadDataCall(node, exprType); + this.#analyzeOdataModelV2CreateEntry(node, exprType); + const deprecationInfo = this.getDeprecationInfo(exprType.symbol); if (!deprecationInfo) { return; @@ -354,15 +358,7 @@ export default class SourceFileLinter { return parent; } - analyzeLibInitCall(node: ts.CallExpression) { - if (!ts.isIdentifier(node.expression) && // Assignment `const LibInit = Library.init` and destructuring - !ts.isPropertyAccessExpression(node.expression) && /* Lib.init() */ - !ts.isElementAccessExpression(node.expression) /* Lib["init"]() */) { - return; - } - - const nodeExp = node.expression; - const nodeType = this.#checker.getTypeAtLocation(nodeExp); + #analyzeLibInitCall(node: ts.CallExpression, nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "init") { return; } @@ -371,6 +367,7 @@ export default class SourceFileLinter { if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/Lib") { return; } + const nodeExp = node.expression; const initArg = node?.arguments[0] && ts.isObjectLiteralExpression(node.arguments[0]) && @@ -443,15 +440,7 @@ export default class SourceFileLinter { }); } - analyzeParametersGetCall(node: ts.CallExpression) { - if (!ts.isIdentifier(node.expression) && - !ts.isPropertyAccessExpression(node.expression) && - !ts.isElementAccessExpression(node.expression)) { - return; - } - - const nodeExp = node.expression; - const nodeType = this.#checker.getTypeAtLocation(nodeExp); + #analyzeParametersGetCall(node: ts.CallExpression, nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "get") { return; } @@ -466,24 +455,10 @@ export default class SourceFileLinter { return; } - this.#reporter.addMessage({ - node, - severity: LintMessageSeverity.Error, - ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: "Usage of deprecated variant of 'sap/ui/core/theming/Parameters.get'", - messageDetails: this.#messageDetails ? "" : undefined, - }); + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_PARAMETERS_GET, node); } - analyzeCreateComponentCall(node: ts.CallExpression) { - if (!ts.isIdentifier(node.expression) && - !ts.isPropertyAccessExpression(node.expression) && - !ts.isElementAccessExpression(node.expression)) { - return; - } - - const nodeExp = node.expression; - const nodeType = this.#checker.getTypeAtLocation(nodeExp); + #analyzeCreateComponentCall(node: ts.CallExpression, nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "createComponent") { return; } @@ -512,27 +487,11 @@ export default class SourceFileLinter { } if (asyncFalseNode) { - this.#reporter.addMessage({ - node: asyncFalseNode, - severity: LintMessageSeverity.Error, - ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: "Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component#createComponent'", - messageDetails: this.#messageDetails ? - "Property 'async' must be either omitted or set to true" : - undefined, - }); + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_CREATE_COMPONENT, asyncFalseNode); } } - analyzeOdataModelV2CreateEntry(node: ts.CallExpression) { - if (!ts.isIdentifier(node.expression) && - !ts.isPropertyAccessExpression(node.expression) && - !ts.isElementAccessExpression(node.expression)) { - return; - } - - const nodeExp = node.expression; - const nodeType = this.#checker.getTypeAtLocation(nodeExp); + #analyzeOdataModelV2CreateEntry(node: ts.CallExpression, nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "createEntry") { return; } @@ -557,26 +516,11 @@ export default class SourceFileLinter { } if (batchGroupId) { - this.#reporter.addMessage({ - node: batchGroupId, - severity: LintMessageSeverity.Error, - ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: - "Usage of deprecated parameter 'batchGroupId' in 'sap/ui/model/odata/v2/ODataModel#createEntry'", - messageDetails: this.#messageDetails ? "Use parameter 'groupId' instead" : undefined, - }); + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY, batchGroupId); } } - analyzeJsonModelLoadDataCall(node: ts.CallExpression) { - if (!ts.isIdentifier(node.expression) && - !ts.isPropertyAccessExpression(node.expression) && - !ts.isElementAccessExpression(node.expression)) { - return; - } - - const nodeExp = node.expression; - const nodeType = this.#checker.getTypeAtLocation(nodeExp); + #analyzeJsonModelLoadDataCall(node: ts.CallExpression, nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "loadData") { return; } @@ -592,15 +536,9 @@ export default class SourceFileLinter { const asyncArg = node.arguments[2]; if (asyncArg.kind === ts.SyntaxKind.FalseKeyword) { - this.#reporter.addMessage({ - node: asyncArg, - severity: LintMessageSeverity.Error, - ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: "Usage of deprecated value for parameter 'bAsync' of 'sap/ui/model/json/JSONModel#loadData'", - messageDetails: this.#messageDetails ? - "Parameter 'bAsync' must be either omitted or set to true" : - undefined, - }); + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA, { + paramName: "bAsync", + }, asyncArg); } if (node.arguments.length < 5) { @@ -608,15 +546,37 @@ export default class SourceFileLinter { } const cacheArg = node.arguments[5]; if (cacheArg.kind === ts.SyntaxKind.FalseKeyword) { - this.#reporter.addMessage({ - node: cacheArg, - severity: LintMessageSeverity.Error, - ruleId: RULES["ui5-linter-no-partially-deprecated-api"], - message: "Usage of deprecated value for parameter 'bCache' of 'sap/ui/model/json/JSONModel#loadData'", - messageDetails: this.#messageDetails ? - "Parameter 'bCache' must be either omitted or set to true" : - undefined, - }); + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA, { + paramName: "bCache", + }, cacheArg); + } + } + + analyzeNewCoreRouter(node: ts.NewExpression, nodeType: ts.Type) { + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/routing/Router") { + return; + } + + if (!node.arguments || node.arguments.length < 2 || !ts.isObjectLiteralExpression(node.arguments[1])) { + return; + } + + const configArg = node.arguments[1]; + + let asyncProb; + for (const prop of configArg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + if (prop.name.getText() === "async") { + asyncProb = prop; + break; + } + } + + if (!asyncProb || asyncProb.initializer.kind !== ts.SyntaxKind.TrueKeyword) { + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_CORE_ROUTER, node); } } diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index 07039c74e..297feb5b1 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -4,7 +4,8 @@ sap.ui.define([ "sap/ui/model/odata/v4/ODataModel", "sap/ui/model/odata/v2/ODataModel" "sap/ui/core/Component" -], function(Parameters, JSONModel, ODataModelV4, ODataModelV2, Component) { + "sap/ui/core/routing/Router" +], function(Parameters, JSONModel, ODataModelV4, ODataModelV2, Component, Router) { Parameters.get(); // (deprecated since 1.92) If no parameter is given Parameters.get("sapUiParam1"); // (deprecated since 1.94) If a string is given as first parameter @@ -56,4 +57,8 @@ sap.ui.define([ }); }); + new Router([], {}); // Deprecated: "oConfig.async" must set be true + new Router([], {async: false}); // Deprecated: "oConfig.async" must set be true + new Router([], {async: true}); // Negative test: async true is correct + }); diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index 131ace939..e2a61e704 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -442,14 +442,88 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 1, - fatalErrorCount: 1, + errorCount: 10, + fatalErrorCount: 0, filePath: 'PartialDeprecation.js', messages: [ { - fatal: true, - message: 'Invalid arguments: Missing second argument', - ruleId: 'ui5-linter-parsing-error', + column: 2, + line: 10, + message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', + messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 11, + message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', + messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 12, + message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', + messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 21, + message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', + messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 46, + line: 24, + message: 'Usage of deprecated value for parameter \'bAsync\' of \'sap/ui/model/json/JSONModel#loadData\'', + messageDetails: 'Parameter \'bAsync\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.json.JSONModel%23methods/loadData)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 66, + line: 25, + message: 'Usage of deprecated value for parameter \'bCache\' of \'sap/ui/model/json/JSONModel#loadData\'', + messageDetails: 'Parameter \'bCache\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.json.JSONModel%23methods/loadData)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + line: 33, + message: 'Usage of deprecated parameter \'batchGroupId\' in \'sap/ui/model/odata/v2/ODataModel#createEntry\'', + messageDetails: 'Use parameter \'groupId\' instead. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.odata.v2.ODataModel%23methods/createEntry)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 4, + line: 45, + message: 'Usage of deprecated value for parameter \'async\' of \'sap/ui/core/Component#createComponent\'', + messageDetails: 'Property \'async\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.core.Component%23methods/createComponent)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 60, + message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', + messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 61, + message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', + messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', + ruleId: 'ui5-linter-no-partially-deprecated-api', severity: 2, }, ], diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index d6d54f408032a6668785ca19aa0d03afdb6320e5..6258198d97c0efe7eaade157fb8882a1070afef2 100644 GIT binary patch literal 10196 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 D|C@** literal 9526 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 SQ}IV%FcZFgmMx@1M*2U;D`i*! From c9e25c2693c7ed0237244c330de87fcb84855bb3 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 9 Sep 2024 11:20:54 +0200 Subject: [PATCH 06/12] feat: Detect Mobile#init deprecations --- src/linter/messages.ts | 12 +++++ src/linter/ui5Types/SourceFileLinter.ts | 50 +++++++++++++++++- .../NoDeprecatedApi/PartialDeprecation.js | 14 +++-- .../rules/snapshots/NoDeprecatedApi.ts.md | 38 +++++++++---- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 10196 -> 10350 bytes 5 files changed, 97 insertions(+), 17 deletions(-) diff --git a/src/linter/messages.ts b/src/linter/messages.ts index 70bf6d98a..eb4a6cee9 100644 --- a/src/linter/messages.ts +++ b/src/linter/messages.ts @@ -19,6 +19,7 @@ export enum MESSAGE { PARTIALLY_DEPRECATED_CREATE_COMPONENT, PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY, PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA, + PARTIALLY_DEPRECATED_MOBILE_INIT, PARTIALLY_DEPRECATED_CORE_ROUTER, } export const MESSAGE_INFO = { @@ -190,6 +191,17 @@ export const MESSAGE_INFO = { `{@link sap.ui.model.json.JSONModel#loadData See API reference}`, }, + [MESSAGE.PARTIALLY_DEPRECATED_MOBILE_INIT]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: ({paramName}: {paramName: string}) => + `Usage of deprecated value for parameter '${paramName}' of 'sap/ui/util/Mobile#init'`, + details: ({paramName}: {paramName: string}) => + `Parameter '${paramName}' must be either omitted or set to true. ` + + `{@link sap.ui.util.Mobile#init See API reference}`, + }, + [MESSAGE.PARTIALLY_DEPRECATED_CORE_ROUTER]: { severity: LintMessageSeverity.Error, ruleId: RULES["ui5-linter-no-partially-deprecated-api"], diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index da2c82923..08cea2514 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -180,7 +180,7 @@ export default class SourceFileLinter { } const classType = this.#checker.getTypeAtLocation(node.expression); - this.analyzeNewCoreRouter(node, classType); + this.#analyzeNewCoreRouter(node, classType); // There can be multiple and we need to find the right one const [constructSignature] = classType.getConstructSignatures(); @@ -294,6 +294,7 @@ export default class SourceFileLinter { this.#analyzeCreateComponentCall(node, exprType); this.#analyzeJsonModelLoadDataCall(node, exprType); this.#analyzeOdataModelV2CreateEntry(node, exprType); + this.#analyzeMobileInit(node, exprType); const deprecationInfo = this.getDeprecationInfo(exprType.symbol); if (!deprecationInfo) { @@ -512,6 +513,7 @@ export default class SourceFileLinter { } if (prop.name.getText() === "batchGroupId") { batchGroupId = prop; + break; } } @@ -552,7 +554,51 @@ export default class SourceFileLinter { } } - analyzeNewCoreRouter(node: ts.NewExpression, nodeType: ts.Type) { + #analyzeMobileInit(node: ts.CallExpression, nodeType: ts.Type) { + if (!nodeType.symbol || nodeType.symbol.getName() !== "init") { + return; + } + + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/util/Mobile") { + return; + } + + if (!node.arguments.length || !ts.isObjectLiteralExpression(node.arguments[0])) { + return; + } + const configArg = node.arguments[0]; + let homeIconArg; + let homeIconPrecomposedArg; + for (const prop of configArg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + const propName = prop.name.getText(); + if (propName === "homeIcon") { + homeIconArg = prop; + } else if (propName === "homeIconPrecomposed") { + homeIconPrecomposedArg = prop; + } + + if (homeIconPrecomposedArg && homeIconArg) { + break; + } + } + + if (homeIconArg) { + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_MOBILE_INIT, { + paramName: "homeIcon", + }, homeIconArg); + } + if (homeIconPrecomposedArg) { + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_MOBILE_INIT, { + paramName: "homeIconPrecomposed", + }, homeIconPrecomposedArg); + } + } + + #analyzeNewCoreRouter(node: ts.NewExpression, nodeType: ts.Type) { const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/routing/Router") { return; diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index 297feb5b1..5fa6cdceb 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -2,10 +2,11 @@ sap.ui.define([ "sap/ui/core/theming/Parameters", "sap/ui/model/json/JSONModel", "sap/ui/model/odata/v4/ODataModel", - "sap/ui/model/odata/v2/ODataModel" - "sap/ui/core/Component" - "sap/ui/core/routing/Router" -], function(Parameters, JSONModel, ODataModelV4, ODataModelV2, Component, Router) { + "sap/ui/model/odata/v2/ODataModel", + "sap/ui/core/Component", + "sap/ui/core/routing/Router", + "sap/ui/util/Mobile" +], function(Parameters, JSONModel, ODataModelV4, ODataModelV2, Component, Router, Mobile) { Parameters.get(); // (deprecated since 1.92) If no parameter is given Parameters.get("sapUiParam1"); // (deprecated since 1.94) If a string is given as first parameter @@ -61,4 +62,9 @@ sap.ui.define([ new Router([], {async: false}); // Deprecated: "oConfig.async" must set be true new Router([], {async: true}); // Negative test: async true is correct + Mobile.init({ + homeIcon: "icon.png", // Deprecated + homeIconPrecomposed: true, // Deprecated + }); + Mobile.init({}); // Negative test: No deprecated parameters }); diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index e2a61e704..43c601db4 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -442,13 +442,13 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 10, + errorCount: 12, fatalErrorCount: 0, filePath: 'PartialDeprecation.js', messages: [ { column: 2, - line: 10, + line: 11, message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -456,7 +456,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 11, + line: 12, message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -464,7 +464,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 12, + line: 13, message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -472,7 +472,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 21, + line: 22, message: 'Usage of deprecated variant of \'sap/ui/core/theming/Parameters.get\'', messageDetails: 'Parameters.get (https://ui5.sap.com/1.120/#/api/sap.ui.core.theming.Parameters%23methods/sap.ui.core.theming.Parameters.get)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -480,7 +480,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 46, - line: 24, + line: 25, message: 'Usage of deprecated value for parameter \'bAsync\' of \'sap/ui/model/json/JSONModel#loadData\'', messageDetails: 'Parameter \'bAsync\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.json.JSONModel%23methods/loadData)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -488,7 +488,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 66, - line: 25, + line: 26, message: 'Usage of deprecated value for parameter \'bCache\' of \'sap/ui/model/json/JSONModel#loadData\'', messageDetails: 'Parameter \'bCache\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.json.JSONModel%23methods/loadData)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -496,7 +496,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 3, - line: 33, + line: 34, message: 'Usage of deprecated parameter \'batchGroupId\' in \'sap/ui/model/odata/v2/ODataModel#createEntry\'', messageDetails: 'Use parameter \'groupId\' instead. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.odata.v2.ODataModel%23methods/createEntry)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -504,7 +504,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 4, - line: 45, + line: 46, message: 'Usage of deprecated value for parameter \'async\' of \'sap/ui/core/Component#createComponent\'', messageDetails: 'Property \'async\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.core.Component%23methods/createComponent)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -512,7 +512,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 60, + line: 61, message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -520,12 +520,28 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 61, + line: 62, message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', ruleId: 'ui5-linter-no-partially-deprecated-api', severity: 2, }, + { + column: 3, + line: 66, + message: 'Usage of deprecated value for parameter \'homeIcon\' of \'sap/ui/util/Mobile#init\'', + messageDetails: 'Parameter \'homeIcon\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.util.Mobile%23methods/init)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + line: 67, + message: 'Usage of deprecated value for parameter \'homeIconPrecomposed\' of \'sap/ui/util/Mobile#init\'', + messageDetails: 'Parameter \'homeIconPrecomposed\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.util.Mobile%23methods/init)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, ], warningCount: 0, }, diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index 6258198d97c0efe7eaade157fb8882a1070afef2..844965a8cbc3895daf734b2d371baa2798800b56 100644 GIT binary patch literal 10350 zcmX|nbyO72_cq-nNGvQM(%sz%NOyO4EK*BJFG_cJh%`ty%Sy9!=PoKpuaW}l>*xDB z=bdxzotbBzGjq@UGiRQA6-^Xh82Z?Q{M~#5UIYmfV4@MDpVm)KcRx4h$~)!w>lJeG zR~^`#M7kO8pb=;L;2p z$zWiL!)s{jtUU0wRAKLaN!Vqtfq^qrV-&ex^9%Cw z60%dARHiekVXPdPT57rBoHG>PO=2#Boa2Xiqp~$CSnl5DR$#?OBbF5Mj(mN~f+7gMm30C4NTb zuQmGH6cQl@o7?2!FQAdEty6k0U>pEi=X@?02Eb$z)I(HM`Ai{?sCF9V4dBZ}ashlY zk$ix+oUlvh`zoTyJYtAj-CE@3h91jS&~4=m2Q1OOM!}5I)R9Prw5hCp?SS|bpdIeOPh-WZk=+N!_k&~8@<>jl0{m^BY_B) z$DanrG!Zk^f211-YQmKB8<{1-b73KAKFd6RBI;qmyqJw*7q$ywJDZHd6~Z~*4&(_E|Xv+S`h&v5#!!58d2Ef|2r5x+y>1!UZ8<&$OP|>a&#g-#xr%U zvjb0+61wwJq7u)CBW69Re8>z0U+v}Ng;0(y*bv$BL++BG#u%0wSnDz+r{=66AN(By zjI`{LMuYEs@!J~M>)|D*6g8*>gZq!qf6mxN0Ic+IbaU{Vv8C2YXAoIJ9J~p2- ? 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 H(9!-MZ6eeX literal 10196 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 D|C@** From f2da53c8f3bcee00abf171aef8b761891f5fd64a Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 9 Sep 2024 16:09:06 +0200 Subject: [PATCH 07/12] refactor: Fix ESLint error --- src/linter/ui5Types/SourceFileLinter.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 08cea2514..9108f102e 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -288,7 +288,7 @@ export default class SourceFileLinter { throw new Error(`Unhandled CallExpression expression syntax: ${ts.SyntaxKind[exprNode.kind]}`); } - this.#analyzeLibInitCall(node, exprType); // Check for sap/ui/core/Lib.init usages + this.#analyzeLibInitCall(node, exprNode, exprType); // Check for sap/ui/core/Lib.init usages // Check for partially deprecated calls this.#analyzeParametersGetCall(node, exprType); this.#analyzeCreateComponentCall(node, exprType); @@ -359,7 +359,10 @@ export default class SourceFileLinter { return parent; } - #analyzeLibInitCall(node: ts.CallExpression, nodeType: ts.Type) { + #analyzeLibInitCall( + node: ts.CallExpression, + exprNode: ts.CallExpression | ts.ElementAccessExpression | ts.PropertyAccessExpression | ts.Identifier, + nodeType: ts.Type) { if (!nodeType.symbol || nodeType.symbol.getName() !== "init") { return; } @@ -368,7 +371,6 @@ export default class SourceFileLinter { if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/Lib") { return; } - const nodeExp = node.expression; const initArg = node?.arguments[0] && ts.isObjectLiteralExpression(node.arguments[0]) && @@ -395,10 +397,10 @@ export default class SourceFileLinter { if (nodeToHighlight) { let importedVarName: string; - if (ts.isIdentifier(nodeExp)) { - importedVarName = nodeExp.getText(); + if (ts.isIdentifier(exprNode)) { + importedVarName = exprNode.getText(); } else { - importedVarName = nodeExp.expression.getText() + ".init"; + importedVarName = exprNode.expression.getText() + ".init"; } this.#reporter.addMessage(MESSAGE.LIB_INIT_API_VERSION, { From 408ac60ba53efd218cb0efed6e9b3513988cb5fd Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 9 Sep 2024 17:20:23 +0200 Subject: [PATCH 08/12] refactor: Move checks for function calls --- src/linter/ui5Types/SourceFileLinter.ts | 94 +++++++------------------ 1 file changed, 26 insertions(+), 68 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 9108f102e..e531036af 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -288,13 +288,26 @@ export default class SourceFileLinter { throw new Error(`Unhandled CallExpression expression syntax: ${ts.SyntaxKind[exprNode.kind]}`); } - this.#analyzeLibInitCall(node, exprNode, exprType); // Check for sap/ui/core/Lib.init usages - // Check for partially deprecated calls - this.#analyzeParametersGetCall(node, exprType); - this.#analyzeCreateComponentCall(node, exprType); - this.#analyzeJsonModelLoadDataCall(node, exprType); - this.#analyzeOdataModelV2CreateEntry(node, exprType); - this.#analyzeMobileInit(node, exprType); + const moduleDeclaration = this.getSymbolModuleDeclaration(exprType.symbol); + if (exprType.symbol && moduleDeclaration) { + const symbolName = exprType.symbol.getName(); + const moduleName = moduleDeclaration.name.text; + + if (symbolName === "init" && moduleName === "sap/ui/core/Lib") { + // Check for sap/ui/core/Lib.init usages + this.#analyzeLibInitCall(node, exprNode); + } else if (symbolName === "get" && moduleName === "sap/ui/core/theming/Parameters") { + this.#analyzeParametersGetCall(node); + } else if (symbolName === "createComponent" && moduleName === "sap/ui/core/Component") { + this.#analyzeCreateComponentCall(node); + } else if (symbolName === "loadData" && moduleName === "sap/ui/model/json/JSONModel") { + this.#analyzeJsonModelLoadDataCall(node); + } else if (symbolName === "createEntry" && moduleName === "sap/ui/model/odata/v2/ODataModel") { + this.#analyzeOdataModelV2CreateEntry(node); + } else if (symbolName === "init" && moduleName === "sap/ui/util/Mobile") { + this.#analyzeMobileInit(node); + } + } const deprecationInfo = this.getDeprecationInfo(exprType.symbol); if (!deprecationInfo) { @@ -361,17 +374,7 @@ export default class SourceFileLinter { #analyzeLibInitCall( node: ts.CallExpression, - exprNode: ts.CallExpression | ts.ElementAccessExpression | ts.PropertyAccessExpression | ts.Identifier, - nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "init") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/Lib") { - return; - } - + exprNode: ts.CallExpression | ts.ElementAccessExpression | ts.PropertyAccessExpression | ts.Identifier) { const initArg = node?.arguments[0] && ts.isObjectLiteralExpression(node.arguments[0]) && node.arguments[0]; @@ -443,16 +446,7 @@ export default class SourceFileLinter { }); } - #analyzeParametersGetCall(node: ts.CallExpression, nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "get") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/theming/Parameters") { - return; - } - + #analyzeParametersGetCall(node: ts.CallExpression) { if (node.arguments.length && ts.isObjectLiteralExpression(node.arguments[0])) { // Non-deprecated usage return; @@ -461,16 +455,7 @@ export default class SourceFileLinter { this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_PARAMETERS_GET, node); } - #analyzeCreateComponentCall(node: ts.CallExpression, nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "createComponent") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/Component") { - return; - } - + #analyzeCreateComponentCall(node: ts.CallExpression) { if (!node.arguments.length || !ts.isObjectLiteralExpression(node.arguments[0])) { return; } @@ -494,16 +479,7 @@ export default class SourceFileLinter { } } - #analyzeOdataModelV2CreateEntry(node: ts.CallExpression, nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "createEntry") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/model/odata/v2/ODataModel") { - return; - } - + #analyzeOdataModelV2CreateEntry(node: ts.CallExpression) { if (!node.arguments.length || node.arguments.length < 2 || !ts.isObjectLiteralExpression(node.arguments[1])) { return; } @@ -524,16 +500,7 @@ export default class SourceFileLinter { } } - #analyzeJsonModelLoadDataCall(node: ts.CallExpression, nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "loadData") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/model/json/JSONModel") { - return; - } - + #analyzeJsonModelLoadDataCall(node: ts.CallExpression) { if (!node.arguments.length || node.arguments.length < 2) { return; } @@ -556,16 +523,7 @@ export default class SourceFileLinter { } } - #analyzeMobileInit(node: ts.CallExpression, nodeType: ts.Type) { - if (!nodeType.symbol || nodeType.symbol.getName() !== "init") { - return; - } - - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/util/Mobile") { - return; - } - + #analyzeMobileInit(node: ts.CallExpression) { if (!node.arguments.length || !ts.isObjectLiteralExpression(node.arguments[0])) { return; } From 7c96e2bbbfc6c6a85db9ed7db4bea9b3e4c027b5 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 10 Sep 2024 13:43:10 +0200 Subject: [PATCH 09/12] refactor: Fix checks for v2 and v4.ODataModel --- src/linter/messages.ts | 27 +++++++++- src/linter/ui5Types/SourceFileLinter.ts | 50 +++++++++++++----- .../NoDeprecatedApi/PartialDeprecation.js | 13 +++-- .../rules/snapshots/NoDeprecatedApi.ts.md | 42 +++++++++++---- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 10350 -> 10599 bytes 5 files changed, 107 insertions(+), 25 deletions(-) diff --git a/src/linter/messages.ts b/src/linter/messages.ts index eb4a6cee9..fc6777f5e 100644 --- a/src/linter/messages.ts +++ b/src/linter/messages.ts @@ -18,9 +18,11 @@ export enum MESSAGE { PARTIALLY_DEPRECATED_PARAMETERS_GET, PARTIALLY_DEPRECATED_CREATE_COMPONENT, PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY, + PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY_PROPERTIES_ARRAY, PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA, PARTIALLY_DEPRECATED_MOBILE_INIT, PARTIALLY_DEPRECATED_CORE_ROUTER, + PARTIALLY_DEPRECATED_ODATA_MODEL_V4, } export const MESSAGE_INFO = { @@ -180,6 +182,17 @@ export const MESSAGE_INFO = { `{@link sap.ui.model.odata.v2.ODataModel#createEntry See API reference}`, }, + [MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY_PROPERTIES_ARRAY]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated value for parameter 'properties' in 'sap/ui/model/odata/v2/ODataModel#createEntry'`, + details: () => + `Passing a list of property names is deprecated. Pass the initial values as an object instead. ` + + `{@link sap.ui.model.odata.v2.ODataModel#createEntry See API reference}`, + }, + [MESSAGE.PARTIALLY_DEPRECATED_JSON_MODEL_LOAD_DATA]: { severity: LintMessageSeverity.Error, ruleId: RULES["ui5-linter-no-partially-deprecated-api"], @@ -207,10 +220,22 @@ export const MESSAGE_INFO = { ruleId: RULES["ui5-linter-no-partially-deprecated-api"], message: () => - `Usage of deprecated value for parameter 'oConfig.async' of constructor of 'sap/ui/core/Router'`, + `Usage of deprecated value for parameter 'oConfig.async' of constructor 'sap/ui/core/Router'`, details: () => `Parameter 'oConfig.async' must be set to true. ` + `{@link sap/ui/core/routing/Router#constructor See API reference}`, }, + [MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V4]: { + severity: LintMessageSeverity.Error, + ruleId: RULES["ui5-linter-no-partially-deprecated-api"], + + message: () => + `Usage of deprecated parameter 'mParameters.synchronizationMode' ` + + `of constructor 'sap/ui/model/odata/v4/ODataModel'`, + details: () => + `Parameter 'synchronizationMode' is obsolete and must be omitted. ` + + `{@link sap/ui/model/odata/v4/ODataModel#constructor See API reference}`, + }, + } as const; diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index e531036af..4eaffebab 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -180,7 +180,12 @@ export default class SourceFileLinter { } const classType = this.#checker.getTypeAtLocation(node.expression); - this.#analyzeNewCoreRouter(node, classType); + const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); + if (moduleDeclaration?.name.text === "sap/ui/core/routing/Router") { + this.#analyzeNewCoreRouter(node); + } else if (moduleDeclaration?.name.text === "sap/ui/model/odata/v4/ODataModel") { + this.#analyzeNewOdataModelV4(node); + } // There can be multiple and we need to find the right one const [constructSignature] = classType.getConstructSignatures(); @@ -485,19 +490,26 @@ export default class SourceFileLinter { } const secondArg = node.arguments[1]; let batchGroupId; + let properties; for (const prop of secondArg.properties) { if (!ts.isPropertyAssignment(prop)) { continue; } if (prop.name.getText() === "batchGroupId") { batchGroupId = prop; - break; + } + if (prop.name.getText() === "properties") { + properties = prop; } } if (batchGroupId) { this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY, batchGroupId); } + if (properties && ts.isArrayLiteralExpression(properties.initializer)) { + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY_PROPERTIES_ARRAY, + properties); + } } #analyzeJsonModelLoadDataCall(node: ts.CallExpression) { @@ -540,10 +552,6 @@ export default class SourceFileLinter { } else if (propName === "homeIconPrecomposed") { homeIconPrecomposedArg = prop; } - - if (homeIconPrecomposedArg && homeIconArg) { - break; - } } if (homeIconArg) { @@ -558,12 +566,7 @@ export default class SourceFileLinter { } } - #analyzeNewCoreRouter(node: ts.NewExpression, nodeType: ts.Type) { - const moduleDeclaration = this.getSymbolModuleDeclaration(nodeType.symbol); - if (!moduleDeclaration || moduleDeclaration.name.text !== "sap/ui/core/routing/Router") { - return; - } - + #analyzeNewCoreRouter(node: ts.NewExpression) { if (!node.arguments || node.arguments.length < 2 || !ts.isObjectLiteralExpression(node.arguments[1])) { return; } @@ -586,6 +589,29 @@ export default class SourceFileLinter { } } + #analyzeNewOdataModelV4(node: ts.NewExpression) { + if (!node.arguments || node.arguments.length < 1 || !ts.isObjectLiteralExpression(node.arguments[0])) { + return; + } + + const configArg = node.arguments[0]; + + let synchronizationModeProb; + for (const prop of configArg.properties) { + if (!ts.isPropertyAssignment(prop)) { + continue; + } + if (prop.name.getText() === "synchronizationMode") { + synchronizationModeProb = prop; + break; + } + } + + if (synchronizationModeProb) { + this.#reporter.addMessage(MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V4, synchronizationModeProb); + } + } + getDeprecationInfoForAccess(node: ts.AccessExpression): DeprecationInfo | null { let symbol; if (ts.isPropertyAccessExpression(node)) { diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index 5fa6cdceb..dde2766aa 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -26,14 +26,21 @@ sap.ui.define([ jsonModel.loadData("/api/users", undefined, true, "GET", false, false); // TODO detect: Parameter bCache is deprecated as of Version 1.107 (default=true) var v4Model = new ODataModelV4({ - synchronizationMode: "None" // TODO detect: Parameter "synchronizationMode" is deprecated since 1.110 + synchronizationMode: "None" // Parameter "synchronizationMode" is deprecated since 1.110 + }); + var v4Model = new ODataModelV4({ + synchronizationMode: true // Parameter "synchronizationMode" is deprecated since 1.110 + }); + var v4Model = new ODataModelV4({ + serviceUrl: "my-service" // Negative test: Deprecated parameter is omitted }); var v2Model = new ODataModelV2(); v2Model.createEntry("somePath", { - batchGroupId: "id-123", // TODO detect: Deprecated - use groupId instead - properties: ["property1", "property2"] // TODO detect: Passing a list of property names is deprecated since 1.120; pass the initial values as an object instead + batchGroupId: "id-123", // Deprecated - use groupId instead + properties: ["property1", "property2"] // Passing a list of property names is deprecated since 1.120; pass the initial values as an object instead }); + v2Model.createEntry("somePath"); // Negative test: No deprecated parameters Component.create({ name: "my.comp", diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index 43c601db4..6a4578d57 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -442,7 +442,7 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 12, + errorCount: 15, fatalErrorCount: 0, filePath: 'PartialDeprecation.js', messages: [ @@ -496,15 +496,39 @@ Generated by [AVA](https://avajs.dev). }, { column: 3, - line: 34, + line: 29, + message: 'Usage of deprecated parameter \'mParameters.synchronizationMode\' of constructor \'sap/ui/model/odata/v4/ODataModel\'', + messageDetails: 'Parameter \'synchronizationMode\' is obsolete and must be omitted. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/model/odata/v4/ODataModel#constructor)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + line: 32, + message: 'Usage of deprecated parameter \'mParameters.synchronizationMode\' of constructor \'sap/ui/model/odata/v4/ODataModel\'', + messageDetails: 'Parameter \'synchronizationMode\' is obsolete and must be omitted. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/model/odata/v4/ODataModel#constructor)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + line: 40, message: 'Usage of deprecated parameter \'batchGroupId\' in \'sap/ui/model/odata/v2/ODataModel#createEntry\'', messageDetails: 'Use parameter \'groupId\' instead. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.odata.v2.ODataModel%23methods/createEntry)', ruleId: 'ui5-linter-no-partially-deprecated-api', severity: 2, }, + { + column: 3, + line: 41, + message: 'Usage of deprecated value for parameter \'properties\' in \'sap/ui/model/odata/v2/ODataModel#createEntry\'', + messageDetails: 'Passing a list of property names is deprecated. Pass the initial values as an object instead. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.model.odata.v2.ODataModel%23methods/createEntry)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, { column: 4, - line: 46, + line: 53, message: 'Usage of deprecated value for parameter \'async\' of \'sap/ui/core/Component#createComponent\'', messageDetails: 'Property \'async\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.core.Component%23methods/createComponent)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -512,23 +536,23 @@ Generated by [AVA](https://avajs.dev). }, { column: 2, - line: 61, - message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', + line: 68, + message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor \'sap/ui/core/Router\'', messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', ruleId: 'ui5-linter-no-partially-deprecated-api', severity: 2, }, { column: 2, - line: 62, - message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor of \'sap/ui/core/Router\'', + line: 69, + message: 'Usage of deprecated value for parameter \'oConfig.async\' of constructor \'sap/ui/core/Router\'', messageDetails: 'Parameter \'oConfig.async\' must be set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap/ui/core/routing/Router#constructor)', ruleId: 'ui5-linter-no-partially-deprecated-api', severity: 2, }, { column: 3, - line: 66, + line: 73, message: 'Usage of deprecated value for parameter \'homeIcon\' of \'sap/ui/util/Mobile#init\'', messageDetails: 'Parameter \'homeIcon\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.util.Mobile%23methods/init)', ruleId: 'ui5-linter-no-partially-deprecated-api', @@ -536,7 +560,7 @@ Generated by [AVA](https://avajs.dev). }, { column: 3, - line: 67, + line: 74, message: 'Usage of deprecated value for parameter \'homeIconPrecomposed\' of \'sap/ui/util/Mobile#init\'', messageDetails: 'Parameter \'homeIconPrecomposed\' must be either omitted or set to true. See API reference (https://ui5.sap.com/1.120/#/api/sap.ui.util.Mobile%23methods/init)', ruleId: 'ui5-linter-no-partially-deprecated-api', diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index 844965a8cbc3895daf734b2d371baa2798800b56..ad5d174fa01a7ac7084c6a78436d564d7e64c207 100644 GIT binary patch literal 10599 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 literal 10350 zcmX|nbyO72_cq-nNGvQM(%sz%NOyO4EK*BJFG_cJh%`ty%Sy9!=PoKpuaW}l>*xDB z=bdxzotbBzGjq@UGiRQA6-^Xh82Z?Q{M~#5UIYmfV4@MDpVm)KcRx4h$~)!w>lJeG zR~^`#M7kO8pb=;L;2p z$zWiL!)s{jtUU0wRAKLaN!Vqtfq^qrV-&ex^9%Cw z60%dARHiekVXPdPT57rBoHG>PO=2#Boa2Xiqp~$CSnl5DR$#?OBbF5Mj(mN~f+7gMm30C4NTb zuQmGH6cQl@o7?2!FQAdEty6k0U>pEi=X@?02Eb$z)I(HM`Ai{?sCF9V4dBZ}ashlY zk$ix+oUlvh`zoTyJYtAj-CE@3h91jS&~4=m2Q1OOM!}5I)R9Prw5hCp?SS|bpdIeOPh-WZk=+N!_k&~8@<>jl0{m^BY_B) z$DanrG!Zk^f211-YQmKB8<{1-b73KAKFd6RBI;qmyqJw*7q$ywJDZHd6~Z~*4&(_E|Xv+S`h&v5#!!58d2Ef|2r5x+y>1!UZ8<&$OP|>a&#g-#xr%U zvjb0+61wwJq7u)CBW69Re8>z0U+v}Ng;0(y*bv$BL++BG#u%0wSnDz+r{=66AN(By zjI`{LMuYEs@!J~M>)|D*6g8*>gZq!qf6mxN0Ic+IbaU{Vv8C2YXAoIJ9J~p2- ? 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 H(9!-MZ6eeX From 48fed59b61e739bf2b2a49e4a74f491c32ef4fcd Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 10 Sep 2024 13:57:30 +0200 Subject: [PATCH 10/12] refactor: Cleanup todo comment --- .../linter/rules/NoDeprecatedApi/PartialDeprecation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js index dde2766aa..eac02201d 100644 --- a/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js +++ b/test/fixtures/linter/rules/NoDeprecatedApi/PartialDeprecation.js @@ -22,8 +22,8 @@ sap.ui.define([ getParam(); // (deprecated since 1.92) If no parameter is given var jsonModel = new JSONModel(); - jsonModel.loadData("/api/users", undefined, false); // TODO detect: Parameter bAsync is deprecated as of Version 1.107 (default=true) - jsonModel.loadData("/api/users", undefined, true, "GET", false, false); // TODO detect: Parameter bCache is deprecated as of Version 1.107 (default=true) + jsonModel.loadData("/api/users", undefined, false); // Parameter bAsync is deprecated as of Version 1.107 (default=true) + jsonModel.loadData("/api/users", undefined, true, "GET", false, false); // Parameter bCache is deprecated as of Version 1.107 (default=true) var v4Model = new ODataModelV4({ synchronizationMode: "None" // Parameter "synchronizationMode" is deprecated since 1.110 From 1f93042e0b4456e25ca52a2af3a55160c9bdc4fe Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 10 Sep 2024 14:09:16 +0200 Subject: [PATCH 11/12] refactor: Fix eslint after rebase --- src/linter/messages.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linter/messages.ts b/src/linter/messages.ts index fc6777f5e..a9f2e1874 100644 --- a/src/linter/messages.ts +++ b/src/linter/messages.ts @@ -169,7 +169,7 @@ export const MESSAGE_INFO = { message: () => `Usage of deprecated value for parameter 'async' of 'sap/ui/core/Component#createComponent'`, details: () => `Property 'async' must be either omitted or set to true. ` + - `{@link sap.ui.core.Component#createComponent See API reference}`, + `{@link sap.ui.core.Component#createComponent See API reference}`, }, [MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY]: { @@ -179,7 +179,7 @@ export const MESSAGE_INFO = { message: () => `Usage of deprecated parameter 'batchGroupId' in 'sap/ui/model/odata/v2/ODataModel#createEntry'`, details: () => `Use parameter 'groupId' instead. ` + - `{@link sap.ui.model.odata.v2.ODataModel#createEntry See API reference}`, + `{@link sap.ui.model.odata.v2.ODataModel#createEntry See API reference}`, }, [MESSAGE.PARTIALLY_DEPRECATED_ODATA_MODEL_V2_CREATE_ENTRY_PROPERTIES_ARRAY]: { From 6fe4e665728be74eb7e1274f6c1a40f0bccf0714 Mon Sep 17 00:00:00 2001 From: Matthias Osswald Date: Tue, 10 Sep 2024 15:34:26 +0200 Subject: [PATCH 12/12] refactor: Re-use of getPropertyName --- src/linter/ui5Types/SourceFileLinter.ts | 18 ++---------------- src/linter/ui5Types/asyncComponentFlags.ts | 9 +-------- src/linter/ui5Types/utils.ts | 9 +++++++++ 3 files changed, 12 insertions(+), 24 deletions(-) create mode 100644 src/linter/ui5Types/utils.ts diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 4eaffebab..ce18724e4 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -6,6 +6,7 @@ import {MESSAGE} from "../messages.js"; import {RULES} from "../linterReporting.js"; import analyzeComponentJson from "./asyncComponentFlags.js"; import {deprecatedLibraries} from "../../utils/deprecations.js"; +import {getPropertyName} from "./utils.js"; interface DeprecationInfo { symbol: ts.Symbol; @@ -347,28 +348,13 @@ export default class SourceFileLinter { } } - let reportNodeText; - if (ts.isStringLiteralLike(reportNode) || ts.isNumericLiteral(reportNode)) { - reportNodeText = reportNode.text; - } else { - reportNodeText = reportNode.getText(); - } - this.#reporter.addMessage(MESSAGE.DEPRECATED_FUNCTION_CALL, { - functionName: reportNodeText, + functionName: getPropertyName(reportNode), additionalMessage, details: deprecationInfo.messageDetails, }, reportNode); } - getPropertyName(node: ts.PropertyName): string { - if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) { - return node.text; - } else { - return node.getText(); - } - } - getSymbolModuleDeclaration(symbol: ts.Symbol) { let parent = symbol.valueDeclaration?.parent; while (parent && !ts.isModuleDeclaration(parent)) { diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index e39d3b8a1..211d3a35b 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -6,6 +6,7 @@ import LinterContext, {LintMessageSeverity} from "../LinterContext.js"; import jsonMap from "json-source-map"; import type {jsonSourceMapType} from "../manifestJson/ManifestLinter.js"; import {MESSAGE} from "../messages.js"; +import {getPropertyName} from "./utils.js"; type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; type propsRecord = Record