Skip to content

Commit

Permalink
feat: Detect usage of deprecated jQuery.sap API
Browse files Browse the repository at this point in the history
So far, only the usage of global API such as `jQuery.sap` was detected.
However, when using `jQuery` as local variable via a dependency, the
usage of `jQuery.sap` was not detected, although all APIs within that
namespace are deprecated.
  • Loading branch information
matz3 committed Mar 13, 2024
1 parent 4eb2f0b commit c7371f0
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 71 deletions.
1 change: 1 addition & 0 deletions resources/overrides/index.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
import "./jquery.sap.mobile";
import "./jquery.sap";
65 changes: 65 additions & 0 deletions resources/overrides/jquery.sap.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// General deprecation of jQuery.sap namespace
interface JQueryStatic {
/**
* @deprecated since 1.58. To avoid usage of global variables in general, please
* do not use the jQuery.sap namespace any longer. Most of the jQuery.sap functionalities
* are replaced by alternative modules which can be found in the API doc.
*/
sap: object;
}

// Add exports of all jquery.sap.* modules (except for "jquery.sap.promise" which does not export jQuery)
declare module "jquery.sap.act" {
export default jQuery;
}
declare module "jquery.sap.dom" {
export default jQuery;
}
declare module "jquery.sap.encoder" {
export default jQuery;
}
declare module "jquery.sap.events" {
export default jQuery;
}
declare module "jquery.sap.global" {
export default jQuery;
}
declare module "jquery.sap.history" {
export default jQuery;
}
declare module "jquery.sap.keycodes" {
export default jQuery;
}
declare module "jquery.sap.mobile" {
export default jQuery;
}
declare module "jquery.sap.properties" {
export default jQuery;
}
declare module "jquery.sap.resources" {
export default jQuery;
}
declare module "jquery.sap.script" {
export default jQuery;
}
declare module "jquery.sap.sjax" {
export default jQuery;
}
declare module "jquery.sap.storage" {
export default jQuery;
}
declare module "jquery.sap.strings" {
export default jQuery;
}
declare module "jquery.sap.stubs" {
export default jQuery;
}
declare module "jquery.sap.trace" {
export default jQuery;
}
declare module "jquery.sap.ui" {
export default jQuery;
}
declare module "jquery.sap.xml" {
export default jQuery;
}
4 changes: 0 additions & 4 deletions resources/overrides/jquery.sap.mobile.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,3 @@ interface JQueryStatic {
*/
device: object;
}

declare module "jquery.sap.mobile" {
export default jQuery;
}
39 changes: 30 additions & 9 deletions src/detectors/typeChecker/FileLinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,32 @@ export default class FileLinter {

const symbol = this.isDeprecatedAccess(node);
if (symbol) {
this.#reporter.addMessage({
node,
severity: LintMessageSeverity.Error,
ruleId: "ui5-linter-no-deprecated-property",
message:
`Access of deprecated property ` +
`'${symbol.escapedName as string}'`,
messageDetails: this.extractDeprecatedMessage(symbol),
});
const messageDetails = this.extractDeprecatedMessage(symbol);
if (this.isSymbolOfJquerySapType(symbol)) {
let namespace;
if (ts.isPropertyAccessExpression(node)) {
namespace = this.extractNamespace(node);
}
this.#reporter.addMessage({
node,
severity: LintMessageSeverity.Error,
ruleId: "ui5-linter-no-deprecated-api",
message:
`Use of deprecated API ` +
`'${namespace ?? "jQuery.sap"}'`,
messageDetails,
});
} else {
this.#reporter.addMessage({
node,
severity: LintMessageSeverity.Error,
ruleId: "ui5-linter-no-deprecated-property",
message:
`Access of deprecated property ` +
`'${symbol.escapedName as string}'`,
messageDetails,
});
}
}
}

Expand Down Expand Up @@ -372,6 +389,10 @@ export default class FileLinter {
return false;
}

isSymbolOfJquerySapType(symbol: ts.Symbol) {
return symbol.valueDeclaration?.getSourceFile().fileName === "/types/@ui5/linter/overrides/jquery.sap.d.ts";
}

findClassOrInterface(node: ts.Node): ts.Type | undefined {
let nodeType: ts.Type | undefined = this.#checker.getTypeAtLocation(node);
if (nodeType.isClassOrInterface()) {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

17 changes: 17 additions & 0 deletions test/fixtures/linter/rules/NoDeprecatedApi/jQuery.sap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
sap.ui.define(["sap/ui/thirdparty/jquery", "jquery.sap.properties"], function(importedJQuery, importedJQuerySapProperties) {

// Global access
var oProperties1 = jQuery.sap.properties(); // jQuery.sap.properties is deprecated
var oProperties2 = jQuery["sap"].properties(); // jQuery.sap.properties is deprecated
var oProperties3 = jQuery["sap"]["properties"](); // jQuery.sap.properties is deprecated

// via thirdparty jQuery
var oProperties1 = importedJQuery.sap.properties(); // jQuery.sap.properties is deprecated
var oProperties2 = importedJQuery["sap"].properties(); // jQuery.sap.properties is deprecated
var oProperties3 = importedJQuery["sap"]["properties"](); // jQuery.sap.properties is deprecated

// via jquery.sap module
var oProperties1 = importedJQuerySapProperties.sap.properties(); // jQuery.sap.properties is deprecated
var oProperties2 = importedJQuerySapProperties["sap"].properties(); // jQuery.sap.properties is deprecated
var oProperties3 = importedJQuerySapProperties["sap"]["properties"](); // jQuery.sap.properties is deprecated
});
2 changes: 1 addition & 1 deletion test/fixtures/linter/rules/NoGlobals/NoGlobals.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ sap.ui.define(["sap/ui/core/mvc/Controller"],

jQuery.ajax(); // ERROR: Global third-party variable "jQuery"
jQuery("#foo"); // ERROR: Global third-party variable "jQuery"
jQuery.sap.require(); // ERROR: Global variable "jQuery.sap"
jQuery.sap.require(); // ERROR: Global + deprecated variable "jQuery.sap"

QUnit.test(); // OK: Global third-party variable "QUnit"
sinon.stub(); // OK: Global third-party variable "sinon"
Expand Down
195 changes: 148 additions & 47 deletions test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ Generated by [AVA](https://avajs.dev).
},
]

## General: jQuery.sap-global.js
## General: jQuery.sap.js

> Snapshot 1
Expand All @@ -645,68 +645,169 @@ Generated by [AVA](https://avajs.dev).
coverageInfo: [
{
category: 1,
column: 20,
line: 2,
column: 21,
line: 4,
message: 'Unable to analyze this method call because the type of identifier "properties" in "jQuery.sap.properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 5,
message: 'Unable to analyze this method call because the type of identifier "properties" in "jQuery["sap"].properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 6,
message: 'Unable to analyze this method call because the type of identifier in "jQuery["sap"]["properties"]()"" could not be determined',
},
{
category: 1,
column: 21,
line: 9,
message: 'Unable to analyze this method call because the type of identifier "properties" in "importedJQuery.sap.properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 10,
message: 'Unable to analyze this method call because the type of identifier "properties" in "importedJQuery["sap"].properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 11,
message: 'Unable to analyze this method call because the type of identifier in "importedJQuery["sap"]["properties"]()"" could not be determined',
},
{
category: 1,
column: 21,
line: 14,
message: 'Unable to analyze this method call because the type of identifier "properties" in "importedJQuerySapProperties.sap.properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 15,
message: 'Unable to analyze this method call because the type of identifier "properties" in "importedJQuerySapProperties["sap"].properties()"" could not be determined',
},
{
category: 1,
column: 21,
line: 16,
message: 'Unable to analyze this method call because the type of identifier in "importedJQuerySapProperties["sap"]["properties"]()"" could not be determined',
},
],
errorCount: 1,
errorCount: 12,
fatalErrorCount: 0,
filePath: 'jQuery.sap-global.js',
filePath: 'jQuery.sap.js',
messages: [
{
column: 20,
column: 21,
fatal: undefined,
line: 2,
line: 4,
message: 'Access of global variable \'jQuery\' (jQuery.sap.properties)',
ruleId: 'ui5-linter-no-globals-js',
severity: 2,
},
],
warningCount: 0,
},
]

## General: jQuery.sap-jquery.js

> Snapshot 1
[
{
coverageInfo: [
{
category: 1,
column: 20,
line: 2,
message: 'Unable to analyze this method call because the type of identifier "properties" in "jQuery.sap.properties()"" could not be determined',
column: 21,
fatal: undefined,
line: 4,
message: 'Use of deprecated API \'jQuery.sap.properties\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
],
errorCount: 0,
fatalErrorCount: 0,
filePath: 'jQuery.sap-jquery.js',
messages: [],
warningCount: 0,
},
]

## General: jQuery.sap-module.js

> Snapshot 1
[
{
coverageInfo: [
{
category: 1,
column: 20,
line: 2,
message: 'Unable to analyze this method call because the type of identifier "properties" in "jQuery.sap.properties()"" could not be determined',
column: 21,
fatal: undefined,
line: 5,
message: 'Access of global variable \'jQuery\' (jQuery)',
ruleId: 'ui5-linter-no-globals-js',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 5,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 6,
message: 'Access of global variable \'jQuery\' (jQuery)',
ruleId: 'ui5-linter-no-globals-js',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 6,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 9,
message: 'Use of deprecated API \'importedJQuery.sap.properties\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 10,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 11,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 14,
message: 'Use of deprecated API \'importedJQuerySapProperties.sap.properties\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 15,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
{
column: 21,
fatal: undefined,
line: 16,
message: 'Use of deprecated API \'jQuery.sap\'',
messageDetails: 'Deprecated test message',
ruleId: 'ui5-linter-no-deprecated-api',
severity: 2,
},
],
errorCount: 0,
fatalErrorCount: 0,
filePath: 'jQuery.sap-module.js',
messages: [],
warningCount: 0,
},
]
Expand Down
Binary file modified test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap
Binary file not shown.
Loading

0 comments on commit c7371f0

Please sign in to comment.