From e2bab810d241971423f13817e0186543fdf870ef Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 15 Apr 2024 07:08:27 +0300 Subject: [PATCH 01/90] feat: Analyze async flags --- src/linter/ui5Types/SourceFileLinter.ts | 48 +++++++++++++++++++ .../webapp/Component.js | 1 + 2 files changed, 49 insertions(+) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index a638163a1..7ad508f41 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -67,6 +67,8 @@ export default class SourceFileLinter { node as (ts.PropertyAccessExpression | ts.ElementAccessExpression)); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ImportDeclaration) { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation + } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { + this.analyzeComponentJson(node as ts.ExpressionWithTypeArguments); } // Traverse the whole AST from top to bottom @@ -448,6 +450,52 @@ export default class SourceFileLinter { }); } } + + analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { + if (node.expression.getText() !== "UIComponent") { + return; + } + + let parent = node.parent; + let classDec; + while(!parent || parent.kind !== ts.SyntaxKind.SourceFile) { + if (parent.kind === ts.SyntaxKind.ClassDeclaration) { + classDec = parent; + } + parent = parent.parent; + } + + if (!ts.isSourceFile(parent) || !parent.fileName.includes("Component.js") || !classDec) { + return; + } + + let classInterfaces: ts.ClassElement | undefined; + let classMetadata: ts.ClassElement | undefined; + if (ts.isClassDeclaration(classDec)) { + classDec.members.forEach((classMember) => { + if (classMember.name?.getText() === "interfaces") { + classInterfaces = classMember; + } else if (classMember.name?.getText() === "metadata") { + classMetadata = classMember; + } + }); + } + + if (classInterfaces && ts.isPropertyDeclaration(classInterfaces) && + classInterfaces.initializer && ts.isIntersectionTypeNode(classInterfaces.initializer) && + classInterfaces.initializer.elements && ts.isArrayLiteralExpression(classInterfaces.initializer.elements)) { + const hasAsyncInterface = classInterfaces.initializer + .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); + + if (hasAsyncInterface) { + return; // When the IAsyncContentCreation everything down the stream implicitly becomes async + } + } + + if (classMetadata) { + // TODO: extract manifest object + } + } isSymbolOfUi5Type(symbol: ts.Symbol) { if (symbol.name.startsWith("sap/")) { diff --git a/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js b/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js index ad514a8ab..77a592924 100644 --- a/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js +++ b/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js @@ -2,6 +2,7 @@ sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/Device", "./model/models"], fu "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { manifest: "json" }, From 46b4622c8502f06fd019a568bc06b46c35e50d3f Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 15 Apr 2024 14:16:13 +0300 Subject: [PATCH 02/90] feat: Implement manifest checks --- src/linter/ui5Types/SourceFileLinter.ts | 57 +++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 4 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 7ad508f41..b54c8a387 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -482,8 +482,7 @@ export default class SourceFileLinter { } if (classInterfaces && ts.isPropertyDeclaration(classInterfaces) && - classInterfaces.initializer && ts.isIntersectionTypeNode(classInterfaces.initializer) && - classInterfaces.initializer.elements && ts.isArrayLiteralExpression(classInterfaces.initializer.elements)) { + classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { const hasAsyncInterface = classInterfaces.initializer .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); @@ -491,10 +490,60 @@ export default class SourceFileLinter { return; // When the IAsyncContentCreation everything down the stream implicitly becomes async } } + + let manifestJson; + if (classMetadata && ts.isPropertyDeclaration(classMetadata) && + classMetadata.initializer && ts.isObjectLiteralExpression(classMetadata.initializer)) { + manifestJson = this.extractPropsRecursive(classMetadata.initializer); + } + + if (manifestJson?.manifest.value === "\"json\"") { // The manifest is an external manifest.json file + // TODO: Read manifest.json from file system + } - if (classMetadata) { - // TODO: extract manifest object + if (manifestJson?.manifest) { + // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 + if (manifestJson?.["sap.ui5"]?.rootView?.async === true && + manifestJson?.["sap.ui5"]?.routing?.config?.async === true + ) { + return; + } } + + this.#reporter.addMessage({ + node: classMetadata ?? classInterfaces ?? classDec, + severity: LintMessageSeverity.Error, + ruleId: "ui5-linter-no-sync-loading", + message: "zzzz", + messageDetails: "", + }); + } + + extractPropsRecursive = (node: ts.ObjectLiteralExpression) => { + const properties: Record = Object.create(null); + + node.properties?.forEach((prop) => { + if (!ts.isPropertyAssignment(prop) || !prop.name) { + return; + } + + const key = prop.name.getText(); + if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { + properties[key] = { value: false, node: prop.initializer }; + } else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) { + properties[key] = { value: null, node: prop.initializer }; + } if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { + properties[key] = { value: this.extractPropsRecursive(prop.initializer), node: prop.initializer }; + } else if ( + (ts.isIdentifier(prop.initializer) || + ts.isNumericLiteral(prop.initializer) || + ts.isStringLiteral(prop.initializer)) + + && prop.initializer.text) { + properties[key] = { value: prop.initializer.getText(), node: prop.initializer }; + } + }); + return properties; } isSymbolOfUi5Type(symbol: ts.Symbol) { From 6e32f58bd1569634486041dd4333d5227947b3ee Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 16 Apr 2024 07:58:19 +0300 Subject: [PATCH 03/90] feat: Extend linting further --- src/linter/ui5Types/SourceFileLinter.ts | 51 ++++++++++++++----------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index b54c8a387..1aec5ece6 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -16,6 +16,7 @@ export default class SourceFileLinter { #boundVisitNode: (node: ts.Node) => void; #reportCoverage: boolean; #messageDetails: boolean; + #context: LinterContext; constructor( context: LinterContext, resourcePath: ResourcePath, sourceFile: ts.SourceFile, sourceMap: string | undefined, @@ -451,57 +452,60 @@ export default class SourceFileLinter { } } - analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { + async analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { if (node.expression.getText() !== "UIComponent") { return; } let parent = node.parent; - let classDec; + let classDesc; while(!parent || parent.kind !== ts.SyntaxKind.SourceFile) { if (parent.kind === ts.SyntaxKind.ClassDeclaration) { - classDec = parent; + classDesc = parent; } parent = parent.parent; } - if (!ts.isSourceFile(parent) || !parent.fileName.includes("Component.js") || !classDec) { + if (!ts.isSourceFile(parent) || !parent.fileName.includes("Component.js") || !classDesc) { return; } let classInterfaces: ts.ClassElement | undefined; - let classMetadata: ts.ClassElement | undefined; - if (ts.isClassDeclaration(classDec)) { - classDec.members.forEach((classMember) => { + let componentManifest: ts.ClassElement | undefined; + if (ts.isClassDeclaration(classDesc)) { + classDesc.members.forEach((classMember) => { if (classMember.name?.getText() === "interfaces") { classInterfaces = classMember; } else if (classMember.name?.getText() === "metadata") { - classMetadata = classMember; + componentManifest = classMember; } }); } - + + let hasAsyncInterface: boolean = false; if (classInterfaces && ts.isPropertyDeclaration(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { - const hasAsyncInterface = classInterfaces.initializer + hasAsyncInterface = classInterfaces.initializer .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); - - if (hasAsyncInterface) { - return; // When the IAsyncContentCreation everything down the stream implicitly becomes async - } } let manifestJson; - if (classMetadata && ts.isPropertyDeclaration(classMetadata) && - classMetadata.initializer && ts.isObjectLiteralExpression(classMetadata.initializer)) { - manifestJson = this.extractPropsRecursive(classMetadata.initializer); + if (componentManifest && ts.isPropertyDeclaration(componentManifest) && + componentManifest.initializer && ts.isObjectLiteralExpression(componentManifest.initializer)) { + manifestJson = this.extractPropsRecursive(componentManifest.initializer); } if (manifestJson?.manifest.value === "\"json\"") { // The manifest is an external manifest.json file // TODO: Read manifest.json from file system - } - - if (manifestJson?.manifest) { + const reader = this.#context.getRootReader(); + const manifestPath = this.#resourcePath.replace("Component.js", "manifest.json"); + // const manifestResource = await reader.byPath(manifestPath); + const manifestResource = await reader.byGlob("manifest.json"); + + console.log(manifestPath); + } + + if (!hasAsyncInterface && manifestJson?.manifest) { // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 if (manifestJson?.["sap.ui5"]?.rootView?.async === true && manifestJson?.["sap.ui5"]?.routing?.config?.async === true @@ -511,11 +515,12 @@ export default class SourceFileLinter { } this.#reporter.addMessage({ - node: classMetadata ?? classInterfaces ?? classDec, + node: classDesc, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", - message: "zzzz", - messageDetails: "", + message: "Use of sync loading for Component's views", + messageDetails: `Configure the Component.js to implement the "sap.ui.core.IAsyncContentCreation" interface` + + `or set the "sap.ui5/rootView/async" and "sap.ui5/routing/config/async" flags to true.`, }); } From cda4880811430e669dbc7cc760492fd296ddcbd9 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 16 Apr 2024 12:07:14 +0300 Subject: [PATCH 04/90] fix: JSON "parse" improvement --- src/linter/ui5Types/SourceFileLinter.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 1aec5ece6..84777d640 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -507,8 +507,8 @@ export default class SourceFileLinter { if (!hasAsyncInterface && manifestJson?.manifest) { // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 - if (manifestJson?.["sap.ui5"]?.rootView?.async === true && - manifestJson?.["sap.ui5"]?.routing?.config?.async === true + if (manifestJson?.manifest?.value["\"sap.ui5\""]?.value.rootView?.value.async?.value === true && + manifestJson?.manifest?.value["\"sap.ui5\""]?.value.routing?.value.config?.value.async?.value === true ) { return; } @@ -533,19 +533,33 @@ export default class SourceFileLinter { } const key = prop.name.getText(); - if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { + if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) { + properties[key] = { value: true, node: prop.initializer }; + } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { properties[key] = { value: false, node: prop.initializer }; } else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) { properties[key] = { value: null, node: prop.initializer }; - } if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { + } else if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { properties[key] = { value: this.extractPropsRecursive(prop.initializer), node: prop.initializer }; + } else if (ts.isArrayLiteralExpression(prop.initializer)) { + const resolvedValue = prop.initializer.elements.map((elem) => { + if (!ts.isObjectLiteralExpression(elem)) { + return; + } + + return this.extractPropsRecursive(elem) + }).filter(($) => $); + + properties[key] = { value: resolvedValue, node: prop.initializer }; } else if ( (ts.isIdentifier(prop.initializer) || ts.isNumericLiteral(prop.initializer) || ts.isStringLiteral(prop.initializer)) - && prop.initializer.text) { + && prop.initializer.getText()) { properties[key] = { value: prop.initializer.getText(), node: prop.initializer }; + } else { + throw new Error("Unhandled property assignment"); } }); return properties; From c980c07ca1d3a613579bcff65add9e83b0316abe Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 16 Apr 2024 16:19:10 +0300 Subject: [PATCH 05/90] feat: Handle variations for error messaging --- src/linter/ui5Types/SourceFileLinter.ts | 126 +++++++++++++++--------- 1 file changed, 79 insertions(+), 47 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 84777d640..60b4c6f6f 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -451,25 +451,25 @@ export default class SourceFileLinter { }); } } - - async analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { + + analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { if (node.expression.getText() !== "UIComponent") { return; } - + let parent = node.parent; let classDesc; - while(!parent || parent.kind !== ts.SyntaxKind.SourceFile) { + while (!parent || parent.kind !== ts.SyntaxKind.SourceFile) { if (parent.kind === ts.SyntaxKind.ClassDeclaration) { classDesc = parent; } parent = parent.parent; } - + if (!ts.isSourceFile(parent) || !parent.fileName.includes("Component.js") || !classDesc) { return; } - + let classInterfaces: ts.ClassElement | undefined; let componentManifest: ts.ClassElement | undefined; if (ts.isClassDeclaration(classDesc)) { @@ -479,14 +479,15 @@ export default class SourceFileLinter { } else if (classMember.name?.getText() === "metadata") { componentManifest = classMember; } - }); + }); } - let hasAsyncInterface: boolean = false; + let hasAsyncInterface = false; if (classInterfaces && ts.isPropertyDeclaration(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { hasAsyncInterface = classInterfaces.initializer - .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); + .elements.some((implementedInterface) => + implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); } let manifestJson; @@ -495,37 +496,68 @@ export default class SourceFileLinter { manifestJson = this.extractPropsRecursive(componentManifest.initializer); } - if (manifestJson?.manifest.value === "\"json\"") { // The manifest is an external manifest.json file - // TODO: Read manifest.json from file system - const reader = this.#context.getRootReader(); - const manifestPath = this.#resourcePath.replace("Component.js", "manifest.json"); - // const manifestResource = await reader.byPath(manifestPath); - const manifestResource = await reader.byGlob("manifest.json"); - - console.log(manifestPath); - } + // if (manifestJson?.manifest.value === "\"json\"") { // The manifest is an external manifest.json file + // // TODO: Read manifest.json from file system + // const reader = this.#context.getRootReader(); + // const manifestPath = this.#resourcePath.replace("Component.js", "manifest.json"); + // // const manifestResource = await reader.byPath(manifestPath); + // const manifestResource = await reader.byGlob("manifest.json"); - if (!hasAsyncInterface && manifestJson?.manifest) { - // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 - if (manifestJson?.manifest?.value["\"sap.ui5\""]?.value.rootView?.value.async?.value === true && - manifestJson?.manifest?.value["\"sap.ui5\""]?.value.routing?.value.config?.value.async?.value === true - ) { - return; + // console.log(manifestPath); + // } + + const manifestSapui5Section = manifestJson?.manifest?.value?.["\"sap.ui5\""]; + const rootViewAsyncValue = manifestSapui5Section?.value.rootView?.value.async?.value; + const rootViewAsyncNode = manifestSapui5Section?.value.rootView?.value.async?.node; + const routeAsyncValue = manifestSapui5Section?.value.routing?.value.config?.value.async?.value; + const routeAsyncNode = manifestSapui5Section?.value.routing?.value.config?.value.async?.node; + + // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 + if (!hasAsyncInterface) { + if (rootViewAsyncValue !== true || routeAsyncValue !== true) { + this.#reporter.addMessage({ + node: classDesc, + severity: LintMessageSeverity.Error, + ruleId: "ui5-linter-no-sync-loading", + message: "Use of sync loading for Component's views", + messageDetails: `Configure the Component.js to implement the ` + + `"sap.ui.core.IAsyncContentCreation" interface or set the ` + + `"sap.ui5/rootView/async" and "sap.ui5/routing/config/async" flags to true.`, + }); + } + } else { + if (rootViewAsyncValue === true) { + this.#reporter.addMessage({ + node: rootViewAsyncNode ?? classDesc, + severity: LintMessageSeverity.Warning, + ruleId: "ui5-linter-no-sync-loading", + message: "Remove the async flag from \"sap.ui5/rootView\"", + messageDetails: `The Component.js is configured to implement the ` + + `"sap.ui.core.IAsyncContentCreation" interface. "sap.ui5/rootView/async" ` + + `and "sap.ui5/rootView/async" flags are implicitly overridden and unnecessary.`, + }); + } + if (routeAsyncValue === true) { + this.#reporter.addMessage({ + node: routeAsyncNode ?? classDesc, + severity: LintMessageSeverity.Warning, + ruleId: "ui5-linter-no-sync-loading", + message: "Remove the async flag from \"sap.ui5/routing/config\"", + messageDetails: `The Component.js is configured to implement the ` + + `"sap.ui.core.IAsyncContentCreation" interface. "sap.ui5/rootView/async" ` + + `and "sap.ui5/routing/config/async" flags are implicitly overridden and unnecessary.`, + }); } } - - this.#reporter.addMessage({ - node: classDesc, - severity: LintMessageSeverity.Error, - ruleId: "ui5-linter-no-sync-loading", - message: "Use of sync loading for Component's views", - messageDetails: `Configure the Component.js to implement the "sap.ui.core.IAsyncContentCreation" interface` + - `or set the "sap.ui5/rootView/async" and "sap.ui5/routing/config/async" flags to true.`, - }); } - + extractPropsRecursive = (node: ts.ObjectLiteralExpression) => { - const properties: Record = Object.create(null); + type propsRecordValueType = string | boolean | undefined | null | number | object; + type propsRecord = Record; + const properties = Object.create(null) as propsRecord; node.properties?.forEach((prop) => { if (!ts.isPropertyAssignment(prop) || !prop.name) { @@ -534,36 +566,36 @@ export default class SourceFileLinter { const key = prop.name.getText(); if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) { - properties[key] = { value: true, node: prop.initializer }; + properties[key] = {value: true, node: prop.initializer}; } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { - properties[key] = { value: false, node: prop.initializer }; + properties[key] = {value: false, node: prop.initializer}; } else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) { - properties[key] = { value: null, node: prop.initializer }; + properties[key] = {value: null, node: prop.initializer}; } else if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { - properties[key] = { value: this.extractPropsRecursive(prop.initializer), node: prop.initializer }; + properties[key] = {value: this.extractPropsRecursive(prop.initializer), node: prop.initializer}; } else if (ts.isArrayLiteralExpression(prop.initializer)) { const resolvedValue = prop.initializer.elements.map((elem) => { if (!ts.isObjectLiteralExpression(elem)) { return; } - - return this.extractPropsRecursive(elem) + + return this.extractPropsRecursive(elem); }).filter(($) => $); - properties[key] = { value: resolvedValue, node: prop.initializer }; + properties[key] = {value: resolvedValue, node: prop.initializer}; } else if ( (ts.isIdentifier(prop.initializer) || - ts.isNumericLiteral(prop.initializer) || - ts.isStringLiteral(prop.initializer)) + ts.isNumericLiteral(prop.initializer) || + ts.isStringLiteral(prop.initializer)) && - && prop.initializer.getText()) { - properties[key] = { value: prop.initializer.getText(), node: prop.initializer }; + prop.initializer.getText()) { + properties[key] = {value: prop.initializer.getText(), node: prop.initializer}; } else { throw new Error("Unhandled property assignment"); } }); return properties; - } + }; isSymbolOfUi5Type(symbol: ts.Symbol) { if (symbol.name.startsWith("sap/")) { From 7d5711d18bf548d8f815e340cc6cc2964f6c7b1b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 18 Apr 2024 16:16:43 +0300 Subject: [PATCH 06/90] feat: Checks for inline manifest --- src/linter/ui5Types/SourceFileLinter.ts | 103 ++++++++++++++---------- src/linter/ui5Types/TypeLinter.ts | 12 ++- 2 files changed, 72 insertions(+), 43 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 60b4c6f6f..f5a66c7bb 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -1,12 +1,19 @@ import ts, {Identifier} from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; import LinterContext, {ResourcePath, CoverageCategory, LintMessageSeverity} from "../LinterContext.js"; +import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.d.ts"; interface DeprecationInfo { symbol: ts.Symbol; messageDetails?: string; } +type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; +type propsRecord = Record; + export default class SourceFileLinter { #resourcePath: ResourcePath; #sourceFile: ts.SourceFile; @@ -17,11 +24,12 @@ export default class SourceFileLinter { #reportCoverage: boolean; #messageDetails: boolean; #context: LinterContext; + #manifestContent: string | undefined; constructor( context: LinterContext, resourcePath: ResourcePath, sourceFile: ts.SourceFile, sourceMap: string | undefined, checker: ts.TypeChecker, reportCoverage: boolean | undefined = false, - messageDetails: boolean | undefined = false + messageDetails: boolean | undefined = false, manifestContent: string | undefined ) { this.#resourcePath = resourcePath; this.#sourceFile = sourceFile; @@ -31,6 +39,7 @@ export default class SourceFileLinter { this.#boundVisitNode = this.visitNode.bind(this); this.#reportCoverage = reportCoverage; this.#messageDetails = messageDetails; + this.#manifestContent = manifestContent; } // eslint-disable-next-line @typescript-eslint/require-await @@ -490,73 +499,86 @@ export default class SourceFileLinter { implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); } - let manifestJson; + let manifestJson: propsRecord = {}; if (componentManifest && ts.isPropertyDeclaration(componentManifest) && componentManifest.initializer && ts.isObjectLiteralExpression(componentManifest.initializer)) { - manifestJson = this.extractPropsRecursive(componentManifest.initializer); + manifestJson = this.extractPropsRecursive(componentManifest.initializer) ?? {}; } - // if (manifestJson?.manifest.value === "\"json\"") { // The manifest is an external manifest.json file - // // TODO: Read manifest.json from file system - // const reader = this.#context.getRootReader(); - // const manifestPath = this.#resourcePath.replace("Component.js", "manifest.json"); - // // const manifestResource = await reader.byPath(manifestPath); - // const manifestResource = await reader.byGlob("manifest.json"); + let rootViewAsyncFlag: boolean | undefined; + let routingAsyncFlag: boolean | undefined; + let rootViewAsyncFlagNode: ts.Node | undefined; + let routingAsyncFlagNode: ts.Node | undefined; - // console.log(manifestPath); - // } + if (manifestJson.manifest?.value === "\"json\"") { // The manifest is an external manifest.json file + const parsedManifestContent = + JSON.parse(this.#manifestContent ?? "") as SAPJSONSchemaForWebApplicationManifestFile; - const manifestSapui5Section = manifestJson?.manifest?.value?.["\"sap.ui5\""]; - const rootViewAsyncValue = manifestSapui5Section?.value.rootView?.value.async?.value; - const rootViewAsyncNode = manifestSapui5Section?.value.rootView?.value.async?.node; - const routeAsyncValue = manifestSapui5Section?.value.routing?.value.config?.value.async?.value; - const routeAsyncNode = manifestSapui5Section?.value.routing?.value.config?.value.async?.node; + const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; + // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef + rootViewAsyncFlag = rootView?.async as boolean; + routingAsyncFlag = routing?.config?.async; + } else { + /* eslint-disable @typescript-eslint/no-explicit-any */ + const instanceOfPropsRecord = (obj: any): obj is propsRecord => { + return obj && typeof obj === "object"; + }; + + let manifestSapui5Section: propsRecord | undefined; + if (instanceOfPropsRecord(manifestJson.manifest?.value) && + instanceOfPropsRecord(manifestJson.manifest.value["\"sap.ui5\""].value)) { + manifestSapui5Section = manifestJson.manifest.value["\"sap.ui5\""].value; + } + + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && + typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { + rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; + rootViewAsyncFlagNode = manifestSapui5Section?.rootView?.value.async?.node; + } + + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && + typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { + routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; + routingAsyncFlagNode = manifestSapui5Section?.routing?.value.config?.value.async?.node; + } + } - // https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717 if (!hasAsyncInterface) { - if (rootViewAsyncValue !== true || routeAsyncValue !== true) { + if (rootViewAsyncFlag !== true || routingAsyncFlag !== true) { this.#reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", message: "Use of sync loading for Component's views", - messageDetails: `Configure the Component.js to implement the ` + - `"sap.ui.core.IAsyncContentCreation" interface or set the ` + - `"sap.ui5/rootView/async" and "sap.ui5/routing/config/async" flags to true.`, + messageDetails: `https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717`, }); } } else { - if (rootViewAsyncValue === true) { + if (rootViewAsyncFlag === true) { this.#reporter.addMessage({ - node: rootViewAsyncNode ?? classDesc, + node: rootViewAsyncFlagNode ?? classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag from \"sap.ui5/rootView\"", - messageDetails: `The Component.js is configured to implement the ` + - `"sap.ui.core.IAsyncContentCreation" interface. "sap.ui5/rootView/async" ` + - `and "sap.ui5/rootView/async" flags are implicitly overridden and unnecessary.`, + message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", + messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, }); } - if (routeAsyncValue === true) { + if (routingAsyncFlag === true) { this.#reporter.addMessage({ - node: routeAsyncNode ?? classDesc, + node: routingAsyncFlagNode ?? classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag from \"sap.ui5/routing/config\"", - messageDetails: `The Component.js is configured to implement the ` + - `"sap.ui.core.IAsyncContentCreation" interface. "sap.ui5/rootView/async" ` + - `and "sap.ui5/routing/config/async" flags are implicitly overridden and unnecessary.`, + message: "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", + messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, }); } } } extractPropsRecursive = (node: ts.ObjectLiteralExpression) => { - type propsRecordValueType = string | boolean | undefined | null | number | object; - type propsRecord = Record; const properties = Object.create(null) as propsRecord; node.properties?.forEach((prop) => { @@ -578,9 +600,8 @@ export default class SourceFileLinter { if (!ts.isObjectLiteralExpression(elem)) { return; } - return this.extractPropsRecursive(elem); - }).filter(($) => $); + }).filter(($) => $) as propsRecordValueType[]; properties[key] = {value: resolvedValue, node: prop.initializer}; } else if ( @@ -591,7 +612,7 @@ export default class SourceFileLinter { prop.initializer.getText()) { properties[key] = {value: prop.initializer.getText(), node: prop.initializer}; } else { - throw new Error("Unhandled property assignment"); + // throw new Error("Unhandled property assignment"); } }); return properties; diff --git a/src/linter/ui5Types/TypeLinter.ts b/src/linter/ui5Types/TypeLinter.ts index 12cc80c8f..db9e10e06 100644 --- a/src/linter/ui5Types/TypeLinter.ts +++ b/src/linter/ui5Types/TypeLinter.ts @@ -4,7 +4,7 @@ import SourceFileLinter from "./SourceFileLinter.js"; import {taskStart} from "../../util/perf.js"; import {getLogger} from "@ui5/logger"; import LinterContext, {LinterParameters} from "../LinterContext.js"; -// import {Project} from "@ui5/project"; +import path from "node:path/posix"; import {AbstractAdapter} from "@ui5/fs"; import {createAdapter, createResource} from "@ui5/fs/resourceFactory"; @@ -103,12 +103,20 @@ export default class TypeChecker { if (!sourceMap) { log.verbose(`Failed to get source map for ${sourceFile.fileName}`); } + let manifestContent; + if (sourceFile.fileName.endsWith("/Component.js")) { + const res = await this.#workspace.byPath(path.dirname(sourceFile.fileName) + "/manifest.json"); + if (res) { + manifestContent = await res.getString(); + } + } const linterDone = taskStart("Type-check resource", sourceFile.fileName, true); const linter = new SourceFileLinter( this.#context, sourceFile.fileName, sourceFile, sourceMap, - checker, reportCoverage, messageDetails + checker, reportCoverage, messageDetails, + manifestContent ); await linter.lint(); linterDone(); From 4e8d60799a0e77906fa427dae7e8d94b990fc46a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 18 Apr 2024 16:32:36 +0300 Subject: [PATCH 07/90] fix: Tests --- src/linter/ui5Types/SourceFileLinter.ts | 8 ++-- test/lib/linter/_linterHelper.ts | 5 ++- test/lib/linter/snapshots/linter.ts.md | 54 ++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index f5a66c7bb..2a7ad7baa 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -29,7 +29,7 @@ export default class SourceFileLinter { constructor( context: LinterContext, resourcePath: ResourcePath, sourceFile: ts.SourceFile, sourceMap: string | undefined, checker: ts.TypeChecker, reportCoverage: boolean | undefined = false, - messageDetails: boolean | undefined = false, manifestContent: string | undefined + messageDetails: boolean | undefined = false, manifestContent?: string | undefined ) { this.#resourcePath = resourcePath; this.#sourceFile = sourceFile; @@ -512,16 +512,16 @@ export default class SourceFileLinter { if (manifestJson.manifest?.value === "\"json\"") { // The manifest is an external manifest.json file const parsedManifestContent = - JSON.parse(this.#manifestContent ?? "") as SAPJSONSchemaForWebApplicationManifestFile; + JSON.parse(this.#manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef rootViewAsyncFlag = rootView?.async as boolean; routingAsyncFlag = routing?.config?.async; } else { - /* eslint-disable @typescript-eslint/no-explicit-any */ + /* eslint-disable @typescript-eslint/no-explicit-any */ const instanceOfPropsRecord = (obj: any): obj is propsRecord => { - return obj && typeof obj === "object"; + return !!obj && typeof obj === "object"; }; let manifestSapui5Section: propsRecord | undefined; diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 9050b5385..86ac94434 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -28,11 +28,12 @@ export async function esmockDeprecationText() { context: LinterContext, filePath: string, sourceFile: SourceFile, sourceMap: string | undefined, checker: TypeChecker, reportCoverage: boolean | undefined = false, - messageDetails: boolean | undefined = false + messageDetails: boolean | undefined = false, + manifestContent?: string | undefined ) { // Don't use sinon's stubs as it's hard to clean after them in this case and it leaks memory. const linter = new SourceFileLinter( - context, filePath, sourceFile, sourceMap, checker, reportCoverage, messageDetails + context, filePath, sourceFile, sourceMap, checker, reportCoverage, messageDetails, manifestContent ); linter.getDeprecationText = () => "Deprecated test message"; return linter; diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index 0e377b7b8..c99895df0 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -288,8 +288,27 @@ Generated by [AVA](https://avajs.dev). errorCount: 0, fatalErrorCount: 0, filePath: 'webapp/Component.js', - messages: [], - warningCount: 0, + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 2, }, { coverageInfo: [ @@ -773,7 +792,38 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], +<<<<<<< HEAD errorCount: 2, +======= + errorCount: 0, + fatalErrorCount: 0, + filePath: 'webapp/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 2, + }, + { + coverageInfo: [], + errorCount: 1, +>>>>>>> f14afdd (fix: Tests) fatalErrorCount: 0, filePath: 'webapp/controller/App.controller.js', messages: [ From 3280f546bcda7bac2890c9b363b2ebda51697baf Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 18 Apr 2024 16:48:18 +0300 Subject: [PATCH 08/90] fix: Merge conflicts --- src/linter/ui5Types/SourceFileLinter.ts | 1 - test/lib/linter/snapshots/linter.ts.md | 6 +----- test/lib/linter/snapshots/linter.ts.snap | Bin 8056 -> 8433 bytes 3 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 2a7ad7baa..0cfc2b73c 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -23,7 +23,6 @@ export default class SourceFileLinter { #boundVisitNode: (node: ts.Node) => void; #reportCoverage: boolean; #messageDetails: boolean; - #context: LinterContext; #manifestContent: string | undefined; constructor( diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index c99895df0..a1c799a23 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -792,9 +792,6 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], -<<<<<<< HEAD - errorCount: 2, -======= errorCount: 0, fatalErrorCount: 0, filePath: 'webapp/Component.js', @@ -822,8 +819,7 @@ Generated by [AVA](https://avajs.dev). }, { coverageInfo: [], - errorCount: 1, ->>>>>>> f14afdd (fix: Tests) + errorCount: 2, fatalErrorCount: 0, filePath: 'webapp/controller/App.controller.js', messages: [ diff --git a/test/lib/linter/snapshots/linter.ts.snap b/test/lib/linter/snapshots/linter.ts.snap index fdcc391c8ee5db69fe3725b552ba70010cd88341..b08ebfedde70fee8bdb53fb21047f7e2fd0ede2e 100644 GIT binary patch literal 8433 zcmV6-c(txOlpkDo1MMVVx0loNEP_CeIFQ{Cv-pf_=cLn`j^@m;`DC+O} z_WJtuoOxujPdbw(6H=i0qdjx>{_eBa+H0@R837O zi4J+QKA@(Q9yNTzh#Q)cGIcsBG`?6Kd3yT)D^E+FGP4q%x#x zN!lsFbjgk6t&=LFnc8-0-8xbY^^z-_7En_uJ+)cy*G&7B2O&dEw_+-ZtwnPAyWAuQ4OJ#%0VTi#kHQ1AM#7(ACTZ<5Y~EK$(i#`p2D!$1blH!0T90n~@k#5^V?TP_ zAbIV_3$4d8`|*VJ=(B3>y~7Rny5S3Mc*YHXaSILT8QFk-$@@hQe8mGl^?=_C7kCAT z*8w?J2GKIOu?+4mgGb5)NSOoj+W`D20F4!}wgL`T2oRqGvaJesS3zGDys--Is}dl7 z2jp-yTvZLPs)jqN;o)ilQtp7nYe27oQ#J6>8u)UJ00}rCZ>WV+weay;c%l}btrZ{@ zj$Yys1vsjhYLA{8N{gM<{v*=MqI#mgPs^k(5K=vfxTa>(+(Mc!BkY;quD|D?rW{YG zvZ>38rX+^0Rb{g`ZpeMA*{jFosFFy?$JMCPZ&(ScYz`$=S?`wPF;z3;-ElP~2YXaA zD91H9s9&a};)-VORy3tY?NhC%+94bJv(NJN zt-+ui)%z1MS<_AVxGKj~Q%&{7H8oZOHi_tbHkB1&(`=~(Z0goiTa{?8+vBmAs$G`-O0wVR z9WLS;b*S~C5t!?9zb3h10tFhTvPi?s@|2=s;t5ktrQ1chG@+hM_f8|6P6&ncOYH|W zHk>FlNhBh7^{R5Wo=E6}aji$T$79PK(Dl2k!@RKuibmW&%9-J^S!Tj>J z>x1fmnrgH24p+@$uRIvH%aYBMq8Z(Ks!xqspA8-jhr`F@b#mxB*?tVlgK@Jrzf?_^ z4ZS}VRpmYHGU7E@#L@stw1Ml}sNWW=qG9XI8et{S%Rs3+rwX>mGT zMr(K^3*&~I)D6|JSkS=x2)a`FZ^;AlYnsP#qDrQ{Q ztirALnMzu7f!sHux@MTNkrDb~)w53MFOi6>8i}}Ow#VXz)g)I?M< z)DeiNnMz!h>A@Xx$QF;$04nl4_{+*oJT@PuZkYvp=QD&7y*eYtcl1Of^D|_R4@KSuf2i zpqHi<(MwO3V8F1{(Rs0ap2c!fC90u-L`^RuQEx5LOfA>SnR!T2S(sFgG#B8=%px2) zRU(dL1+O4OhNW{-`5{U{K0js^;m2L2m5^LF8jGOh^|?vqk2q1!=g;itNnWxVqaa^~ z)ykRqk=e+3d2SiG9?3T@9w?l+$<`0WzhDeU8TL=LC-Vm>Hk_iBD3rT1$5lE1|T?Jn5qf*u##=z?## zV3r&9i@Pq4Efjys4JX}js~aA0!@s+s#RIAb-s>s6ol<4*_7vztULndsGYIw&!+zPDr=fzs;PEOZy&B%yONBH;$~QjrMNjX zEVM;gDJrwEva+rSE7xwebdjm&^Rl~Ni`wg(7R5A`Xm6L2d?9f&qwI{FvfGzX;@XY_ zqpG{IDs|cfqG!@C_HVxxw0uet&WO_qZGW)eXBKprS z`Rlzf#|syF;eZ!(FFfuAcNwe~ccXo0sXoQl9c!O2vd8#h?DLbz%_19vFHvrecRVVx zo$;a@+B1WZo*RtzD}$rYyZ>=g2BN@eZF|932cm6LJ?}0{bH}bsbh2jM){*Qj61-<@ zv+nzH1JI9#XWa{3u*3zOE>KSoMmM+=0?vw=Ykl?Pdsk;y5)ZMeg>MrDhunTs%pw|Vjb-}k?Fxw3WimN-r4MT2tryD-$ zhOfFINy>!&wKu+Bq)U55+sHw(ARe5gTq!`E5O0amW zDsT4`8^=|R;E`RW)CA1qT-oi@v6{enN9XXJQij9cCnb1Fg5RH3nKN9l%vIQGZNi5P z;+izSQ;B*_JY;yV6o(ACzL!2?IBsg;+^bNoi-triAIrKyPpIL9-V+LTDaoW73+A1( z7dkG_bexlmt)AB*Z%ia?!wJLg`+8rvKfWq#ru6>f3Dwa1)Uc9FI(ySq)AM>$eG(Wr z{o~cZ8-ZJayMd1Yp9Ve;JOMnNnJ4@L_#@zvphkiQ2^LDQR4URVr`hsyQEr4B7~YY( zU&@(GJ}2c&CR>J0CXc&vCX;u#awd~cyV53;6_Ql%CTo zI_x(W54xSZ9je@-5agPpIMK!_TwTiSUbXg$)|Xs#|t-k;XW@s;f3FM zp;p|qa*3n4Z$%lbErUa4aIy^UEQ7C?!E;5eFMYK>nCXL+KDf*WukgX6KKQn;u;rp( z^8LjJZa*~pVY46Ne)y;#zT_96bq?rH{qX<%P+bm@ayVEHx0S=E$_40b2lT0O_)apaRM( zVSOcBUMWDE9nkA4;f6}Ms}dfqgdbIcTm>DX(Q2y$daMefRd7QU+*1YrQU!mjf;pn` zYP$n^aW!nJhO4XLhHAL48h%*~<)RVmQU|oH2A0>rz8Xl?z`JVT`!(=q5qgOOI=>bc z*23mmh}FX1)xy_m;isY<>{bV~st)SwU|AjPuY;3y@aZ~uvQB{RazKAm2mezCv!}t@ zX>ipv_`o#y{4@djG6(dB)8J>*pu8TI)Wgf_;T`qx@p=K;<$!*@9-gj;-_^sc>9B4( z3`~c&Oc$Vsoq{+W9-a3!zRAgf^86N(brFP@Y3Af~lbCB3gilJ_H5c{@?6Z^UG5?dm%y}(K9ZY8db z(y~uaoY>z?F|pY`s`e$#AK>fpcAS$XPLHXHh-F-_nC5W% zeS6{*{%(pXoH>F*`(GnV-n7{hCNDgDYRPNKkZ0{$MXar;o|JvHAhKOeB=jA6e@at_ zvh?0KaeD6>FTJH2E?dt;u%1-9RKqmFFYnjlx%tp%Crq-1JQKx9imQ>(ZmJ_2^~l7@9GGGFwjuwAaY~@KJhg3)eUfS1H45j#4mp7_6E3H$W$qo_TdJ&zX3igWULl5{&NHT zTLXMk$T&^R_)G)*xB>oK$T*__k#h>9H55o|Dv&m}K-&BQX>x(Ipg?TdpBuo{2$hX6 zs}X{Y(B3$b@C9PStZ9VxLZ-z9zS>qGEnFZiB7C@ddn4>=gv%Qt+6Y=B3^l@Q8{t$V z+|~&1Z-h@Y!e<-dpBv#xp`yzQd~id7w2h*i{AVM4zY(4jKCns1=>2^o{G}0mO)#wq z<~EH4Tw36(JH@YtnjqW+YlK2}7bs+3fwcVv(hd|zJ1ACca}#tn!2zLSmlY`FNP)DY z1=5a*AHT8*Vojh4AHQ<+^TMGf`}`+oG4ZLU?0L|yo6_e&xvb0Qj?Ajg&1QYy++5al z(hqV;Gv^6Oo%6CuuOCiIA0>S$m*kqCJBwO3KX(>&a(?bC>XY-+XHmJz{bGK$a_Qrv zW;t6{mz*o>b#kt(&&av5elF+EwdCg9xz>T^+_~1x&AD@}hnsWfTF*7-&b8(TbLU$7 zgSm69n}X?ctsLnO1+#VfeK1FQ`opUiWRv0xa@Bp$f?RdKx*%QMTv@IQvVc_=2psOs zCEX_`{V12TaADRS#ur-%Clz|UHsJOm3vu<`W&?+?NBR@mKI)MZFtD;TG%e-43s9hxdw*dI#iS7>Pge-gg$`(7CDg8j@JiUR61rEypH{-^RRVO8 z1A5sixMCGty9#by1rMx(L#yGI)dIA|0exUKJhU3Vxf*`88mcdZn=gdNE)<|4N4q|A zA^iA4@U4M`YhdFV0kXsa`N0}^b`6xTg_gCjd946h?tnaf5q$R|`0GW`bTO>CSb(f> zKsK#|?dza-9o)PQ?pY^5Ryw`?tOtEPoLUbbT@PPgFF;l~Ah&FQcWr=&Ho!MGz^^t4 zkkt;z7cPM>Ujolw0=|u~V50!J&;j|?M)<=~iw z4sRA9YaNi=x5C|9;jyjoy{+)4tpcRO0r75wifyoD8+2|1b(;XW$N_2F4$HU0{_T+5 z4sY5nKrVJbj&(w`6K?E;yF1~LP64vc0eRC7xMc@Cumirf1D@L|k$tdg9~|5V#y&W;Pk?N9YT^BGbU$3TAKtwm9^5ZLIvtQtcfliF z@SQIBQy0uSC_r{NAg2z&I}X8vhu|BB;FpI4$Q}pevzNnTm%}rc!{084#=`<+uY=(~ zKMcP<40T7K{Rng(fxC~u_l`irQ2~C)0q-~pmmGyFkHWP_;nt(@+)-G31*lgD@XH(Uw5Z&jPRWmoIRC_18 za2qs?Yy%75p3s$8T2jYQ>rbe*#*FkuHYw3-dQy777Tcm4@t(07*SBSg&FWu8i^(Z9%W75Y@5>2( z>g+7;)3t0**HYYGem?Inh<*WI0{0h6(4|G!68RimRHRG4y+mDlw`CAeyc65mLc#d5 zHCk|T-3Eyhn|!8-(jYSB%_U;Wel_ipa8th)OJtn~*(?Yt26MflJ^7CxkH)*`xfajAV^WyDZTYt>*xtQmN3O4s7o+Ou~{LED`$ zBStnZY{S9>E5my&@7A^we_`@+Pm#gzwTy$A?E`V8-FiM?i`omFx8qe>`-{lwQ*jsUJ)x)zoIi$jrh9ltjN8&U-z{ zPAo-hp|jzD=_-w5;f!HtD0m?4qFhg^X}8(7iK`roD+#?P*fu;T32loHs9KwRsMq?p zt5?;s*H0r6**cHc(r)Yx`<F;-1$<9*7T9rMzS*SLf6RM*1Cx;7( zcd1G$rVnbnhc+gYR?bQGrd{Y#b+N6cXG_uTM-j$!_n!h;oia`r@!?sTcpzu!VQFrk zO^=*1HWhR4{(;g6JufEr%`leaiJPj!A=>&iaDwNSP3O- zv@xNWaE(5WOc}cxi?HkFlCW#USeVBlagdy{S)mw;LS#epB+Uw=2|WXNsZR^fPvHu8 zRQdcA?s?*LvGa=aQ#d;XR$4%8%q(yU%JdBbVjsM)MbpL+^UN7DB~Ee&~wB9!!Gw?o#{LD?Q}Lan3c zwC}R+&P1b>gInTh9nu}wVm93^2b7`A?Eg^Q?3L4sw?#f~Qy}Z=Wlmdc%SRM9d@D&58R?hecQQu=Y_cw#7Re`+RFG%vBl8zUw$a}VK z+t}54+1B)wBeZ94rV;ak0*|P%_5HC5cqXW9Opo^4!L@Bk&IWPZm`H?zVM9so&h)9) zuoY?8?6o6kFFh-{Jj;$ZdhghykF|3=-*P>Xv+56*#20cbW^GAYE5WpEr(M_Ny$%_+ zHTX%>a-|_Jk%Oc9LFqO75|eCYT8LNTqCw=<{ZquN0?wYs#Iea)3>Ax&b$(@8LT0`w zSC)lYDfZM-S@lMSFMEu%>dL$Dk(t9-z3~Mtj^i~lFA~=IMQ3E5b*;ZW?OOkU-lrDz ztuKcL<7ThkZ(8css=pkOvks|RosRdbp2>5(?^y|S09$~)#ll&nJ%=12>rUexp~(zkO-GswDTk}e;gy+475`8UWdS%GfVYdG zCmddWe4h%yX9Dna0DcpI+6stQ!286|6V5OjU#x(yRKQOvz+=UZsDyz^xL*uC;qdh1 zd$JOqs)XNGLR}TKSHaCy@R%5SqSm2A&)>42>f7DtZ`r>P+Tr}w@$p|BFMRdpoWDB$ zJYPjRw=ecS&&)XIujWq1Dza^q0BxC$9Jbbs;b^~M>V4s)V)l*_@NmK5yp^KgS|RQL zx`3;I6F`4n$hLwj$Fv{GTXQSNCx=&#mBV4zwhf0}dySNHPx*+Hb5HpPDea!p3Ss7g zwJtd1f|D+|Gqe8tt+-Tlt}?BVr}Nx!u^W!L;YK%n#tr|wXc$!A@7?ehH#B-+T_)P| zJ^54QGrE2Bea{0w^nlw73%#(@3$O9Qd%VS*6Z-zi3y*u@2VU@&!ICoQErZvH;o6)b z%-(-G`-jWm%VqGhGN|*xb{`xUC&2R^(3^blMjw382mk7W|Mo$HA6AOt+7_N+MSaLW zwJYi-BNdJGDRC`w!ic1M-KC0kq>~HBVE8Az*gQ4GM9$17a_dQ@FF73M=2H_V?`z{F zuT+7<=8Zz%epQR9so`bxjPeQ7*-<{ldj=!gF{`9A^j$V_`d&3|`byM}c4xFB51gqp z-ac_EADwC{XXaBW^u}i=PG5E4oC@Q&I4~*OSA}-0B-h>m91M({Z zE3#8VD{5*c(>E(}Q$s6$YG!J9ab<35s8{BuhWAwFJeU7RWzKWCzbfsyJonv;sz$nV zzqTs--G{3L&+mT_vR+u7&3d9*$a+V0Hf#F#e^zJXQO~M@xizq^29DOipcoU?agyP! zuZ20au(lQs)q)|$LUnBUd7J7WSO=Tx;OaVfg%|_1(gB$>4dzdS4b$M*G#CJvgu%s7VFfp2kBij1KMW5t{HG*2HY&hICXj$ z-!T*R&4lDkc=Js7(9B{1g}u9H!GT#|%!0Shf{)G;Ak!R>?XzLeY|v)In`XlYW*75g z?%yy6w$6d*9C+0nxP1;t4X~jBu5A$DGaT^S8sNPR@Q)4f?FRT=1MF>t|J4Zp(kQ^^ zIN(2NgkM;(J(|D@8?mJcZfk<4tsn_=1$cu4zG5z{oePKNf-x6P&4r)Lg+=o~nO7_V zviF90@Va?$-#mEyG~^i(;)s0gt&*W$h7~frOol#LfCL?t3^YS+GlZLAM>BLc!(+|x zw`S-F7InUUBnVdr;gvzSEeQW``uVRxSi7LGFY^hT|A?D2`FjrQitIVOq6F4I-SL!a z+w11p0OsCJ;Z2!h2DYy+h3S)JG-qG`OB0{!3+LX1g0c8Ouq|uxIJt}vcZ$#A7O!-D zsT`^%vUZ>ulEc}zlPm=yI-mIYMWo^(Ns7q)+ef_+1~;>Y);)b9An%=CSG zyr(x2@98xs*&whGKSbBNlX8D-jQp5nHWX403ySoKffDJ4ty*k^X4tC5rcfn{Cq`o9 z-&+ztSL(@OZD{=nS)NucUC?Fy2yWbS_^Ph0mv;qQEkn=_IVdlY^Av`isdei7vKHgf zYf9vowJXP_GqGnDCQ)c?L)o;=cc0;Y1+hW%Tu5S%z>K3vGbIU`{|}^3*Iyr(v9I@&4h;XBjfDW#VornDtb?(Kc05{oALWQ?B4er@7R+Qn5x)_b1np? z%3A0|&TOG0TNXODx9e`(-;|M5qN>wKr)*xHk&b&Quo}3em_bhZNMmQtAm?Uskx?H5 zz6AUbD3hQ~f|vxaEPj9EZVB#_;Bg6lEJ2kEE_K1xqEU|5v7MSe;Jnc_wbm4~tn*u| zOLa$f*-dNRam*gz-sPI`0q$qVOJAwX3})Mh(`Taasc};{?gQOI=eUv^Hb@3-H&qv(3djRjw+yZ*U4c~IZZ{4uL1J`@tA<=Hj?>J$2+5_M9z@I%Z+Y2kb zaFZ9l;Dx`6wp-;6xt^M-;NqfVMt5Z6fMP1Cb9{)H9QKK)FOKLKW4M~RMKRT`c%Ry- TCHu{Dmy7=&SwpEj3c>&Yne4ny literal 8056 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 Date: Thu, 18 Apr 2024 16:49:19 +0300 Subject: [PATCH 09/90] fix: Reset Component.js --- .../linter/projects/com.ui5.troublesome.app/webapp/Component.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js b/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js index 77a592924..ad514a8ab 100644 --- a/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js +++ b/test/fixtures/linter/projects/com.ui5.troublesome.app/webapp/Component.js @@ -2,7 +2,6 @@ sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/Device", "./model/models"], fu "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { manifest: "json" }, From 2a8c08e0115553ea1a38f770bad0454aa90ad9d3 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 18 Apr 2024 16:53:37 +0300 Subject: [PATCH 10/90] fix: Tests --- test/lib/linter/snapshots/linter.ts.md | 50 +---------------------- test/lib/linter/snapshots/linter.ts.snap | Bin 8433 -> 8056 bytes 2 files changed, 2 insertions(+), 48 deletions(-) diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index a1c799a23..0e377b7b8 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -288,27 +288,8 @@ Generated by [AVA](https://avajs.dev). errorCount: 0, fatalErrorCount: 0, filePath: 'webapp/Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', - ruleId: 'ui5-linter-no-sync-loading', - severity: 1, - }, - { - column: 9, - fatal: undefined, - line: 4, - message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', - ruleId: 'ui5-linter-no-sync-loading', - severity: 1, - }, - ], - warningCount: 2, + messages: [], + warningCount: 0, }, { coverageInfo: [ @@ -790,33 +771,6 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'webapp/Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', - ruleId: 'ui5-linter-no-sync-loading', - severity: 1, - }, - { - column: 9, - fatal: undefined, - line: 4, - message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', - ruleId: 'ui5-linter-no-sync-loading', - severity: 1, - }, - ], - warningCount: 2, - }, { coverageInfo: [], errorCount: 2, diff --git a/test/lib/linter/snapshots/linter.ts.snap b/test/lib/linter/snapshots/linter.ts.snap index b08ebfedde70fee8bdb53fb21047f7e2fd0ede2e..fdcc391c8ee5db69fe3725b552ba70010cd88341 100644 GIT binary patch literal 8056 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 TCHu{Dmy7=&SwpEj3c>&Yne4ny From a02fbad66a36f922b0f252dde78960eedfa03f5a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 10:24:08 +0300 Subject: [PATCH 11/90] refactor: Restructure rules tests to use a common execution --- test/lib/linter/_linterHelper.ts | 9 ++++ test/lib/linter/rules/BestPractices.ts | 5 +++ test/lib/linter/rules/CSPCompliance.ts | 9 +--- test/lib/linter/rules/NoGlobals.ts | 9 +--- test/lib/linter/rules/NoPseudoModules.ts | 9 +--- .../rules/snapshots/BestPractices.ts.md | 42 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 0 -> 501 bytes 7 files changed, 62 insertions(+), 21 deletions(-) create mode 100644 test/lib/linter/rules/BestPractices.ts create mode 100644 test/lib/linter/rules/snapshots/BestPractices.ts.md create mode 100644 test/lib/linter/rules/snapshots/BestPractices.ts.snap diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 86ac94434..9dbe3c052 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -2,6 +2,7 @@ import anyTest, {ExecutionContext, TestFn} from "ava"; import sinonGlobal, {SinonStub} from "sinon"; import util from "util"; import {readdirSync} from "node:fs"; +import path from "node:path"; import esmock from "esmock"; import SourceFileLinter from "../../../src/linter/ui5Types/SourceFileLinter.js"; import {SourceFile, TypeChecker} from "typescript"; @@ -125,3 +126,11 @@ export function preprocessLintResultsForSnapshot(res: LintResult[]) { }); return res; } + +export function runLintRulesTests(filePath: string) { + const __dirname = path.dirname(filePath); + const fileName = path.basename(filePath, ".ts"); + const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); + + createTestsForFixtures(fixturesPath); +} diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/BestPractices.ts new file mode 100644 index 000000000..103ec0308 --- /dev/null +++ b/test/lib/linter/rules/BestPractices.ts @@ -0,0 +1,5 @@ +import {fileURLToPath} from "node:url"; +import {runLintRulesTests} from "../_linterHelper.js"; + +const filePath = fileURLToPath(import.meta.url); +runLintRulesTests(filePath); diff --git a/test/lib/linter/rules/CSPCompliance.ts b/test/lib/linter/rules/CSPCompliance.ts index 57b18a4f6..103ec0308 100644 --- a/test/lib/linter/rules/CSPCompliance.ts +++ b/test/lib/linter/rules/CSPCompliance.ts @@ -1,10 +1,5 @@ -import path from "node:path"; import {fileURLToPath} from "node:url"; -import {createTestsForFixtures} from "../_linterHelper.js"; +import {runLintRulesTests} from "../_linterHelper.js"; const filePath = fileURLToPath(import.meta.url); -const __dirname = path.dirname(filePath); -const fileName = path.basename(filePath, ".ts"); -const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); - -createTestsForFixtures(fixturesPath); +runLintRulesTests(filePath); diff --git a/test/lib/linter/rules/NoGlobals.ts b/test/lib/linter/rules/NoGlobals.ts index 57b18a4f6..103ec0308 100644 --- a/test/lib/linter/rules/NoGlobals.ts +++ b/test/lib/linter/rules/NoGlobals.ts @@ -1,10 +1,5 @@ -import path from "node:path"; import {fileURLToPath} from "node:url"; -import {createTestsForFixtures} from "../_linterHelper.js"; +import {runLintRulesTests} from "../_linterHelper.js"; const filePath = fileURLToPath(import.meta.url); -const __dirname = path.dirname(filePath); -const fileName = path.basename(filePath, ".ts"); -const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); - -createTestsForFixtures(fixturesPath); +runLintRulesTests(filePath); diff --git a/test/lib/linter/rules/NoPseudoModules.ts b/test/lib/linter/rules/NoPseudoModules.ts index 57b18a4f6..103ec0308 100644 --- a/test/lib/linter/rules/NoPseudoModules.ts +++ b/test/lib/linter/rules/NoPseudoModules.ts @@ -1,10 +1,5 @@ -import path from "node:path"; import {fileURLToPath} from "node:url"; -import {createTestsForFixtures} from "../_linterHelper.js"; +import {runLintRulesTests} from "../_linterHelper.js"; const filePath = fileURLToPath(import.meta.url); -const __dirname = path.dirname(filePath); -const fileName = path.basename(filePath, ".ts"); -const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); - -createTestsForFixtures(fixturesPath); +runLintRulesTests(filePath); diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md new file mode 100644 index 000000000..d1804248b --- /dev/null +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -0,0 +1,42 @@ +# Snapshot report for `test/lib/linter/rules/BestPractices.ts` + +The actual snapshot is saved in `BestPractices.ts.snap`. + +Generated by [AVA](https://avajs.dev). + +## General: Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [], + warningCount: 0, + }, + ] + +## General: manifest.json + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 1, + filePath: 'manifest.json', + messages: [ + { + fatal: true, + message: 'Unexpected end of JSON input', + ruleId: 'ui5-linter-parsing-error', + severity: 2, + }, + ], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..3b03e634a979c7d44991bb2ecb9e41bdcb76b9ef GIT binary patch literal 501 zcmVRzVr;zFfe#UYLGx;L0wQ)p`wZ)AqK{4 z{G43t+*x<$lnxA342(=&SXw>@dzgs2dBx_9s0-QU08RdSS?(TO|% z#9sN7^Czs?%JfmRXQr9ato^-Xr<|6Vn;7rjUd6HW@)f;np^N!PJrX+r9st;;&L#zq zt(9j))hY}_&>Dz9H;8ttL)}vVZvcD*@EO2&03iW)sl2E&JUZr)C$U)e`+d*`r~|r5 zbV$H0YJq}HS|6DiTRG+fofuGvZ4y;)jjc6y&*a({TWvH3!bEzR?*Cz`m#CDVOFvn> zxs0etG+9d2o3e9q%&u|G`l+;9>2dv~UX5L=#;)FLFZD`kvxT&&)GA>&4`lSJHSzwR zTKfXv2Y@XCcCKq}__x;PQLdqFWo*UUMvYPt>g4~3Bk_TN3&L*=E-}8Ol5y~rfNuo+ zB;dXPCZfSMSYg|4gbfNdMJ2*UuUr0LRo{83`E|x4&vC>$j!Y6geKC9%DV^oMakgXg rln>&nyq&9ugH&nHc92QylpYTXZ%qe|XKa-}D; Date: Fri, 19 Apr 2024 11:11:17 +0300 Subject: [PATCH 12/90] refactor: Linter helper --- test/lib/linter/_linterHelper.ts | 40 +++++++++++++++++--------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 9dbe3c052..be568945c 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -25,20 +25,20 @@ test.before(async (t) => { export async function esmockDeprecationText() { const typeLinterModule = await esmock("../../../src/linter/ui5Types/TypeLinter.js", { "../../../src/linter/ui5Types/SourceFileLinter.js": - function ( - context: LinterContext, filePath: string, sourceFile: SourceFile, - sourceMap: string | undefined, checker: TypeChecker, - reportCoverage: boolean | undefined = false, - messageDetails: boolean | undefined = false, - manifestContent?: string | undefined - ) { - // Don't use sinon's stubs as it's hard to clean after them in this case and it leaks memory. - const linter = new SourceFileLinter( - context, filePath, sourceFile, sourceMap, checker, reportCoverage, messageDetails, manifestContent - ); - linter.getDeprecationText = () => "Deprecated test message"; - return linter; - }, + function ( + context: LinterContext, filePath: string, sourceFile: SourceFile, + sourceMap: string | undefined, checker: TypeChecker, + reportCoverage: boolean | undefined = false, + messageDetails: boolean | undefined = false, + manifestContent?: string | undefined + ) { + // Don't use sinon's stubs as it's hard to clean after them in this case and it leaks memory. + const linter = new SourceFileLinter( + context, filePath, sourceFile, sourceMap, checker, reportCoverage, messageDetails, manifestContent + ); + linter.getDeprecationText = () => "Deprecated test message"; + return linter; + }, }); const lintWorkspaceModule = await esmock("../../../src/linter/lintWorkspace.js", { "../../../src/linter/ui5Types/TypeLinter.js": typeLinterModule, @@ -90,7 +90,7 @@ export function createTestsForFixtures(fixturesPath: string) { } // Executing linting in parallel might lead to OOM errors in the CI // Therefore always use serial - defineTest(`General: ${testName}`, async (t) => { + defineTest(`General: ${path.basename(fixturesPath)}/${testName}`, async (t) => { const filePaths = [fileName]; const {lintFile} = t.context; @@ -127,10 +127,12 @@ export function preprocessLintResultsForSnapshot(res: LintResult[]) { return res; } -export function runLintRulesTests(filePath: string) { - const __dirname = path.dirname(filePath); - const fileName = path.basename(filePath, ".ts"); - const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); +export function runLintRulesTests(filePath: string, fixturesPath?: string) { + if (!fixturesPath) { + const __dirname = path.dirname(filePath); + const fileName = path.basename(filePath, ".ts"); + fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); + } createTestsForFixtures(fixturesPath); } From 9358dd47ff3b6aca9de9a7fd77968b052242916a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 11:12:04 +0300 Subject: [PATCH 13/90] feat: Add tests for Best practices --- .../BestPractices/Negative_1/Component.js | 10 ++++ .../BestPractices/Negative_1/manifest.json | 45 ++++++++++++++++++ .../BestPractices/Negative_2/Component.js | 9 ++++ .../BestPractices/Negative_2/manifest.json | 47 +++++++++++++++++++ .../BestPractices/Positive_1/Component.js | 9 ++++ .../BestPractices/Positive_1/manifest.json | 45 ++++++++++++++++++ .../BestPractices/Positive_2/Component.js | 10 ++++ .../BestPractices/Positive_2/manifest.json | 47 +++++++++++++++++++ test/lib/linter/rules/BestPractices.ts | 11 ++++- 9 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_1/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_2/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_1/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_2/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js new file mode 100644 index 000000000..a444897d9 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js @@ -0,0 +1,10 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json new file mode 100644 index 000000000..b1e865dcf --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "com.ui5.troublesome.app", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "com.ui5.troublesome.app.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "com.ui5.troublesome.app.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js new file mode 100644 index 000000000..fba1394f8 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json new file mode 100644 index 000000000..3f9e40bf1 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json @@ -0,0 +1,47 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "com.ui5.troublesome.app", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "com.ui5.troublesome.app.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "com.ui5.troublesome.app.view", + "controlId": "app", + "controlAggregation": "pages", + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js new file mode 100644 index 000000000..fba1394f8 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json new file mode 100644 index 000000000..b1e865dcf --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "com.ui5.troublesome.app", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "com.ui5.troublesome.app.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "com.ui5.troublesome.app.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js new file mode 100644 index 000000000..a444897d9 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js @@ -0,0 +1,10 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json new file mode 100644 index 000000000..3f9e40bf1 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json @@ -0,0 +1,47 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "com.ui5.troublesome.app", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "com.ui5.troublesome.app.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "com.ui5.troublesome.app.view", + "controlId": "app", + "controlAggregation": "pages", + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/BestPractices.ts index 103ec0308..391712c30 100644 --- a/test/lib/linter/rules/BestPractices.ts +++ b/test/lib/linter/rules/BestPractices.ts @@ -1,5 +1,14 @@ import {fileURLToPath} from "node:url"; import {runLintRulesTests} from "../_linterHelper.js"; +import path from "node:path"; const filePath = fileURLToPath(import.meta.url); -runLintRulesTests(filePath); +const __dirname = path.dirname(filePath); +const fileName = path.basename(filePath, ".ts"); +const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); + +runLintRulesTests(fileName, path.join(fixturesPath, "Negative_1")); +runLintRulesTests(fileName, path.join(fixturesPath, "Negative_2")); + +runLintRulesTests(fileName, path.join(fixturesPath, "Positive_1")); +runLintRulesTests(fileName, path.join(fixturesPath, "Positive_2")); From 752483426aecb8d2740fb237017e9450f02c5460 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 11:14:31 +0300 Subject: [PATCH 14/90] fix: Tests --- .../rules/snapshots/BestPractices.ts.md | 90 ++++++++++++++++-- .../rules/snapshots/BestPractices.ts.snap | Bin 501 -> 861 bytes .../rules/snapshots/CSPCompliance.ts.md | 4 +- .../rules/snapshots/CSPCompliance.ts.snap | Bin 821 -> 825 bytes .../rules/snapshots/NoDeprecatedApi.ts.md | 46 ++++----- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 6736 -> 6753 bytes .../linter/rules/snapshots/NoGlobals.ts.md | 4 +- .../linter/rules/snapshots/NoGlobals.ts.snap | Bin 1596 -> 1599 bytes .../rules/snapshots/NoPseudoModules.ts.md | 4 +- .../rules/snapshots/NoPseudoModules.ts.snap | Bin 657 -> 658 bytes test/lib/linter/snapshots/linter.ts.md | 12 +-- test/lib/linter/snapshots/linter.ts.snap | Bin 8056 -> 8061 bytes 12 files changed, 118 insertions(+), 42 deletions(-) diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index d1804248b..3d34dac98 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -4,7 +4,7 @@ The actual snapshot is saved in `BestPractices.ts.snap`. Generated by [AVA](https://avajs.dev). -## General: Component.js +## General: Negative_1/Component.js > Snapshot 1 @@ -19,7 +19,34 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: manifest.json +## General: Negative_1/manifest.json + +> Snapshot 1 + + [] + +## General: Negative_2/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [], + warningCount: 0, + }, + ] + +## General: Negative_2/manifest.json + +> Snapshot 1 + + [] + +## General: Positive_1/Component.js > Snapshot 1 @@ -27,16 +54,65 @@ Generated by [AVA](https://avajs.dev). { coverageInfo: [], errorCount: 1, - fatalErrorCount: 1, - filePath: 'manifest.json', + fatalErrorCount: 0, + filePath: 'Component.js', messages: [ { - fatal: true, - message: 'Unexpected end of JSON input', - ruleId: 'ui5-linter-parsing-error', + column: 9, + fatal: undefined, + line: 4, + message: 'Use of sync loading for Component\'s views', + messageDetails: 'https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717', + ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, ], warningCount: 0, }, ] + +## General: Positive_1/manifest.json + +> Snapshot 1 + + [] + +## General: Positive_2/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 2, + }, + ] + +## General: Positive_2/manifest.json + +> Snapshot 1 + + [] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 3b03e634a979c7d44991bb2ecb9e41bdcb76b9ef..4d670a89a26d1e4183d359a4983dab955674d665 100644 GIT binary patch literal 861 zcmV-j1ETyvRzVVd zW|L`mXTr`TwFeK1pcg%e2SE_@?#ZkE2=97Pyy?}mCQWL(Ra1(=58Tttyz}wS^FGfr z`!tvhwLfp}J`+~jP+WIU2_<449&yi!Dz~yJt`)s09o4lG$`X?vO3-~W@dIy_?Fmmb7*J?v;~v_Z6!KGz;<##>0#RJ>!yf#RZOcugYwu$tQ*@X;#kL1 zx}j`)D22p?e84RaPxhIW3uGwHb6ZxtGM4Izbql!rdj*WRl7TR-HK|{@0Bk5`IXP9)zDz2jSdX0^Soq4A{kh z!wk5^fX@u@oCM10RVZf@iD!HrHX_x*a6=-RZe!T)Ww#_^sZc7>S(i%0vK^SZ{e72= zaCP9CMdiDp<`t=`ZlGg#8SK5rZA!6_#C2bL$k$FagtA##wLmrNl4;G zD5fjj?#_lB9}T6lA|6$Gv~`8i&J~heGNLJBX%{=Fu+>`c(c)mW-tRF;kN^J1VBK0D z*kiCxsT1p`b>{&Aj|h0yPw%Xa^7AFVZzB5G(mJ)Je}Dl+2Fx&Eo&k3l@PPpr9pGLc z>E|f-+yP!Vz-tHioxwwI+?*y9GVj@nbZ;#!-XobGEUBOb3yZ|T5-uVYb|KHkb^N-Haror(pwQma8Z n3H`R=W7+n>OWkEpE&w2`Fr~U`N%&t2@U`N2Dz9) literal 501 zcmVRzVr;zFfe#UYLGx;L0wQ)p`wZ)AqK{4 z{G43t+*x<$lnxA342(=&SXw>@dzgs2dBx_9s0-QU08RdSS?(TO|% z#9sN7^Czs?%JfmRXQr9ato^-Xr<|6Vn;7rjUd6HW@)f;np^N!PJrX+r9st;;&L#zq zt(9j))hY}_&>Dz9H;8ttL)}vVZvcD*@EO2&03iW)sl2E&JUZr)C$U)e`+d*`r~|r5 zbV$H0YJq}HS|6DiTRG+fofuGvZ4y;)jjc6y&*a({TWvH3!bEzR?*Cz`m#CDVOFvn> zxs0etG+9d2o3e9q%&u|G`l+;9>2dv~UX5L=#;)FLFZD`kvxT&&)GA>&4`lSJHSzwR zTKfXv2Y@XCcCKq}__x;PQLdqFWo*UUMvYPt>g4~3Bk_TN3&L*=E-}8Ol5y~rfNuo+ zB;dXPCZfSMSYg|4gbfNdMJ2*UuUr0LRo{83`E|x4&vC>$j!Y6geKC9%DV^oMakgXg rln>&nyq&9ugH&nHc92QylpYTXZ%qe|XKa-}D; Snapshot 1 @@ -74,7 +74,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: NoInlineJS_negative.html +## General: CSPCompliance/NoInlineJS_negative.html > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap b/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap index c5a1b68803b565e1a39e1f549050ae567cb0c382..072f8874b733dc85070687444a94d1d95cd29e49 100644 GIT binary patch literal 825 zcmV-91IGM8RzVZR#ayd{2M4&9up_WO% z4B#4oI{=;m_yAy#fW6c_NIO+t;I^dHZ`t495843IKpTll1Z*M&qz+J@?Jx3xRr!qP z_@EqyDAkH(co6u(wBPV#yp%>_L(XB6xyRPoWjMm+B_`*8+Y*%GN4cvWWz={WvMLV~ zC-q%sfhWA`s>`C3j5dBs8$W~e`vg29;0XcG33y4sYXaU=JNR@GycUE1L^1d*(Vi4q zzp)U>R4gAxQiGsqKGekntf6 zd`ttH3T#(_!z!?(0^cL8CG1*<{k#TLG~lKN+|_`m8t_#EuIRv1Jz>{7>~D48oeuoe zfh`8G-vBNdz?Vpy3A@o@KVt%OCUDgRZkxbk6ZmWb^$hShldzi|_E#C;O$PXu0S2=` zF$;(+@F~)L345la-1S8LXtwV*YF@K)Qi-SkX*YRAmmd8Kn`<@u|e z?&^9ji64sy00000000B+m%ncuMHI(B@AmfBos+W@3VswExB!&gUF^g$jt~+G2$>>S ziikjpi01ZY?G5YQV|UJpk&qxIe*g^~Jk@Rz`%iP4t(suO$UB;;HnEZ-HP3vvj5=1k1qV_!lNFX_TX&~ zekrtHv3pbY3qD-*;T<17^x=jNKl?Cjz>P-5?oZjjZNT>p_^km)n$T@R)P%c*o~zg! zQ|0bf>cRxiqR?DH!zcU-NL`D3r;x}ApYQIe}rx1+Mu z+j)>hLsPLH9$R13Mn!QxS-yBSO^i-V`@9ZDS!8zG8)+N`yX~j9j2Y%HL4rS8)5iQZz*q{Arag?dSy9`x1PsT2Ct>RQ-e4Nmrh)s>Us+H!yS+2ENflWY|0 z^}%GiIEq#}ag-RHb%K1@xtB!eUJ{*slkjrAql;IL`N;pseqqM`z}P=BV}D@mAD^*5 zF!sF}`vYUYI%EIu>?bYA6Z^CvmlD0HOtho-??ql;{JRzT#}4E#$uL$v> Snapshot 1 @@ -29,7 +29,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: NoDeprecatedApi.js +## General: NoDeprecatedApi/NoDeprecatedApi.js > Snapshot 1 @@ -198,7 +198,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: NoDeprecatedApi_negative.js +## General: NoDeprecatedApi/NoDeprecatedApi_negative.js > Snapshot 1 @@ -213,7 +213,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: PartialDeprecation.js +## General: NoDeprecatedApi/PartialDeprecation.js > Snapshot 1 @@ -228,7 +228,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: PrototypeClass.js +## General: NoDeprecatedApi/PrototypeClass.js > Snapshot 1 @@ -253,7 +253,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLFragment.fragment.xml +## General: NoDeprecatedApi/XMLFragment.fragment.xml > Snapshot 1 @@ -323,7 +323,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLFragmentDefinition.fragment.xml +## General: NoDeprecatedApi/XMLFragmentDefinition.fragment.xml > Snapshot 1 @@ -393,7 +393,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLHtmlSvg.view.xml +## General: NoDeprecatedApi/XMLHtmlSvg.view.xml > Snapshot 1 @@ -438,7 +438,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLRequire.view.xml +## General: NoDeprecatedApi/XMLRequire.view.xml > Snapshot 1 @@ -463,7 +463,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLTemplatingRequire.view.xml +## General: NoDeprecatedApi/XMLTemplatingRequire.view.xml > Snapshot 1 @@ -497,7 +497,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: XMLView.view.xml +## General: NoDeprecatedApi/XMLView.view.xml > Snapshot 1 @@ -567,7 +567,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: jQuery-device.js +## General: NoDeprecatedApi/jQuery-device.js > Snapshot 1 @@ -610,7 +610,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: jQuery-plugins.js +## General: NoDeprecatedApi/jQuery-plugins.js > Snapshot 1 @@ -654,7 +654,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: jQuery.sap.js +## General: NoDeprecatedApi/jQuery.sap.js > Snapshot 1 @@ -806,7 +806,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: library.js +## General: NoDeprecatedApi/library.js > Snapshot 1 @@ -921,7 +921,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: library_negative.js +## General: NoDeprecatedApi/library_negative.js > Snapshot 1 @@ -936,7 +936,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: manifest.json +## General: NoDeprecatedApi/manifest.json > Snapshot 1 @@ -1136,19 +1136,19 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: manifest_negative.json +## General: NoDeprecatedApi/manifest_negative.json > Snapshot 1 [] -## General: manifest_negative_empty.json +## General: NoDeprecatedApi/manifest_negative_empty.json > Snapshot 1 [] -## General: sap.ui.jsview.js +## General: NoDeprecatedApi/sap.ui.jsview.js > Snapshot 1 @@ -1173,7 +1173,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: sap.ui.require-nested.js +## General: NoDeprecatedApi/sap.ui.require-nested.js > Snapshot 1 @@ -1198,7 +1198,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: sap.ui.require-toplevel.js +## General: NoDeprecatedApi/sap.ui.require-toplevel.js > Snapshot 1 @@ -1223,7 +1223,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: ui5.yaml +## General: NoDeprecatedApi/ui5.yaml > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index 1b59165a3fed7e39b22cf37a8483e0ac9ce4a3b8..e199c7d811fce71b81f3d24a164a4f29f68a3235 100644 GIT binary patch literal 6753 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 DpkTLd literal 6736 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 Snapshot 1 @@ -164,7 +164,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: NoGlobals_Negative.js +## General: NoGlobals/NoGlobals_Negative.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoGlobals.ts.snap b/test/lib/linter/rules/snapshots/NoGlobals.ts.snap index c0d1f72e1a43d6ecd084b90d647a64a45eef7079..9fc83eb78640b3fcb812f54dd1835b9b007983ef 100644 GIT binary patch delta 1593 zcmV-92FCfk48IJ2K~_N^Q*L2!b7*gLAa*kf0{|L4lUY(A!Slh51}}@7OtBoGoMyZT z5Ys^MM|vm?lc^tz2mk;800003<(b=W9Mv7iKWFT{cz3<`UGLgN9T}-M3Eq~pm3oOP z1!zO05|WT`Q6cT@?y+~=@ys$aYsUysODlQ{P%f&d;DwZb2UMvIswx#BKs?YVs*1k= zBv79#RjR1kJ~TVtUFl*8SLJXr^E{8}V1R^cOk)bHD20RM92)qS+4CDnI6oZN4cQuz~%NN=x%;)on zNkklx72-|-Wif_`6-1`xtV-8dlE>{u2a%&Bv|(RLx~}8i=JaeoXc`x3Wkhb#@D1x5 z$}p5s$wkwWCk?+dO1ha*a7)i_x~1fb^gLrpddf6snKi?;O?zo;rld%HDB!OG{wCmG z0%98EHJH)hvl`r@!4YjM<*_Z4lOl6WgF7|2SA(VoD;k{F;D;JKrNOT>ctwLt8oZ%Q zHmNSzM6hIk(t;&R3-M2l;W{1~1EB@sxqdhngwOPo-~k(dzZf6pd2f7_CmtK+IT{<~ zc_cQ<^T*gI&);LCJPYwro=$utPg;my_rncSAN0diA6e``0&YyeZ3!?E@MuDL0LQmJ zfJqUXPeLOJCz4<#;U`H&5(`NVO~5S^aB2da3HbShB8i72Urxc-Q*bT?kEGy*lp;xl zB)6vFjx=ffqOErnt|st@LEQZOoSx&O~ScJcx)10nuOOU6-g>2 z`EC{#v+zU~Udh5cSw)f#NzUb8q;{5B8&&coq? zBF%=Rrwedj0agp}Yyo~(fPWO==At6ag{0pq!s#M^bc=AI2(K35KSlULNs;D5(z{D= ze+kwu4}Go#moCSjl%P>oq=k_5L>bPM!7am6W%x}QVih=2QKZF?^nnUAEAagayi|eL zD^RGy9aTkI3Q0Rvu&Z#P3a?h--6|ZIf-_T!v>cN9Q}FN*z@8dvv^mf_1K$6X)nLPF_}w;ZdtVh?&%^|)o)a?m%S z^d$yc&EQ)58E0*yX-VC8bi+2R^@pYIcT7)zUy**tY3nV+vh=2G89lGxA$5PfD|Kg4 zH`~(o%|%nX`fNv9UFm+aXSaOQv1fJD)@NHi&u>^}v$3^v{-)Vkz2)?*wr)GV-jsS< z`qEu7ZQ0&s6xj$Ak6#NEu6(Fxy7KOIyS2f=GrEnQ+1S*69TDUr5M0<51Z$?h|hFPZ*S2kM$q{2?z|_YwYax9l&=d1 zzhn4&i^GBKIf%!u9fl1A%cpwMT@N4(+OMN~J;J?r4cvQvuQ~V@n6_g#`qz<`7xto{#>^yI2^O@FwW+71Aet`dOyhldJaZf5|l zqjU9X-l_A5`cQmvN6xptw)P>0h#FDMM`GA0arUA0h>B2rZHLycuz&4C8WDAWkoZdU z_ul_92V<|L+T8Cc^sXx3Rua)y?VigYwQ;HqP%u1UEz=IJ9#F zyXro%EAFFy3miP_1=Vd^c3s)8!Q1-LlgEe7H<$Et%1qh8Ot(wlFfDJ`Jazl0Gx^f< z^}(?1(cQ2W-KTf6V06tWe8ZzizWMEr`o42QE*ZYLDzA9vC!V~fXMS%29|1K1hj)7B rclK(}{M5s|t32|nT#;39YY$!h+23|YdRzL&H}(A&t6<`4#vK3viy0%{ literal 1596 zcmV-C2E+M5RzVR-@Gt++-) zs;JstG&|m1>@%syiekkUd-cva=Xc)uJ!f{#yL(<;Y+6q1d)^ZlrEmI{>>ZP~bPelk z`U&TlS z3-K?F;W{1~1EB@sxqdhngwOTE@gRJ+AI5_4lYSTv!h?OUi6DG1upQ({2Ms?TALe;~ ze3U018|66~8|8U4Hp=t6*eK7(u~D9d_$W^&zL6&_#IO3{hN-{y!&Dzx>_7rOpMcvE zU?kwNgz^B6Z+!rhA~v6dMiNdW!Aio@NktM1Ne)fG%@c5H0-Oo>>4YMQha|V8;2SA8 zmx4!A@N!C#Btnu~({M)`I%#+^4HwgjBpH&N%)qxZu$qAvGw?=6kxYan_f5jNNqBq` zUYUfqClyI5BzY(ci&=Ow3$JD2ovb2Bha~56(9Xe+a&R#Rf66J6j4DZ-%EP^R=;h(L zJp3jP|H;GQf+Ed^q^ApTUjbGN@O%M&TY!HS;HIJ?&4r|Q7U6Uex<$B9gx8Dk-y(de zq)782={+U5zXWTShrUpPOPAwMO3)}P(n3gjq6}xs;FjUpGW@y>u?ifiDAHm``alJm z75IJyUa7#_6)05Uj;bOpg`}M-*j2bth1aX_ZWRtp!I>#VS`JD5DR^WGUY>%trri*F(e7WSf>w{fLDE;x4WA#?-L9ePF zw@h0O`X-dV#9*r#Tx&n!tZg(csr!y@*oL+Kh}8X#>FF!d?>KF}WmuNplr5v@^*f~Q zuXm;HEb3-k+P=AHN>`ulNUJN|Z}se!Z#wp@Zrb{6tLOO*%WO8bcFx~8JFB;xp4HZE z$Jd)uZ%bdgE2b^myNn_mf#Qj4fx?v!_e@vbvu?LGICw_4(K8#H+OH#mTm*s(yMkcN zwA;?wcls!1AKW`I@)0n8yo)dzd+M<$M38u9S4b=c1@W1V>Fq5V#RwWt?aq5bT8n#& zL;1RJ@H>XTw>TWwo`ZP&+F{s0uzac~-Sq&%p#3_!*CX6}*TB8!_nL!mfoVH-qkkP~ zIlir>q|zG;ezyl#iOFs3syfwf<7lfTJ+JRzPfi z8`XPsdzL)j9$waZ=2sRh)ApsiU^@#N6M75F>i+;qPp(SW^oOgd?EpaODgmf}c&Gs8 zb_U=&I#-|OojQ-G55<>v&)_laF`AN5<{;8`!IZrif!%6<*r){mY%K6Jjhq@Pn}$_{3_UHXP;dBf(Z+drMj zm!7W=hHa1ThOOv6y_*H2YewN4obR3gT=;w5;hU@SiYI;InQMB|_XptbKuy5m uou2faz1ovL^$71O5Be%sWEI@n!&iUex7|VBmcH>#eg6Z`%J9vx9RL8EO&VAL diff --git a/test/lib/linter/rules/snapshots/NoPseudoModules.ts.md b/test/lib/linter/rules/snapshots/NoPseudoModules.ts.md index 0b645c4f1..5f5ca628a 100644 --- a/test/lib/linter/rules/snapshots/NoPseudoModules.ts.md +++ b/test/lib/linter/rules/snapshots/NoPseudoModules.ts.md @@ -4,7 +4,7 @@ The actual snapshot is saved in `NoPseudoModules.ts.snap`. Generated by [AVA](https://avajs.dev). -## General: NoPseudoModules.js +## General: NoPseudoModules/NoPseudoModules.js > Snapshot 1 @@ -38,7 +38,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: NoPseudoModules_negative.js +## General: NoPseudoModules/NoPseudoModules_negative.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap b/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap index 7c19573fcf8e1f2eec3b7d8f169fe6f1a9d4779a..2ebbf88bc186b46813989722a4954d92980c7160 100644 GIT binary patch literal 658 zcmV;D0&V?4RzVlvWsA!>}$l0 zaXtDNqK1u+VhW}K90f2*)d{McHAbuvm8*Ka4jKXxXqf0sd8oDu;4Xk?0Nw)l3}7Dt zhpFGFdUbJ`TaJS7%klAX&?u-18Y5aDU@wKB$^?zH^a>l%SpgJZgDEEfg7;R>C zu3V9dDDW!k9pOZJ!7GDT6?bIH^TI8ai9K6M6@%%Y28%PcR&?2V%|=#*QBrjW?~4Zz zh64y=3ZD}2oPd`!$U5>_2L=;=@^}DM27umn>^*Yb{QVX<%vcrm1EOTy0JN9V{=CT z$B8Yku#s-<$J=*}Yxq}Ov*smf-2(T75l$QXpK&dX^7u}T@}}ahaB_uz>6rB7pE~9n s0G|LHB;eFe9rMPYI;L-he`uKde?zPoaCLW_b6d0g2F23+QWggQ00)ga@c;k- literal 657 zcmV;C0&e|5RzVzx&?dQ?)~;NuvAMa&xHK4v zc7~-a7axlV00000000Bkls#_~K@f)DxjWmZeAyw0CJ0@DlqQb(5CS0@2na>uBT__x zDA2|p+Z*n7&F-E<3JNHYC=dk=5)x9VXsBqRpyW4D0pbtv3s5dTz!!{AAO%Y_G<;dCT5^!A`oE@629g#YV)ZqbqvZa@x|Dbt{e8F05H;mFU^7cJ|(8t0kPc z9(?ps!PZA1dGi2{0hpokG?mU8BQ}WgRkd0Lje!U>PIM+eR9Odb7r-+BZvlJ;aDad# zG-y=5y1K?qN8a~ktyTj~g36#Nq7?%6lMgCQ(?nDE*@zA=skR1HF+*OyH^#)l93dhSkl&cgll$$zE6E#AYQl?85RVE92K`a%I zI9C}!&*O!qq^FIGbUW&0f<;NDSTtuvuaU||QyXra6J}Az+RPQYO%1x8XD4KA^Yr|n zX)ITbFdLCjt;ld{IdWZ&SfxqSHagjg3>Tkm(wLW8d3Z3DC+e|Oj!j+Z`u2?V?HP+d zPH4H$M!Jn3Z{IVn{$FuT8keMXE8G)CIBo2I#x*y_!=sGxrs9rpvd_PCNP6;59r6u; rPXG=PaOzJT^2Tl*vS@v~G|1WC5X%N!-y5eKX^!6jqok)B_67g|fUquK diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index 0e377b7b8..542a5af9f 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -4,7 +4,7 @@ The actual snapshot is saved in `linter.ts.snap`. Generated by [AVA](https://avajs.dev). -## General: Coverage.js +## General: general/Coverage.js > Snapshot 1 @@ -92,7 +92,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: JSDoc.js +## General: general/JSDoc.js > Snapshot 1 @@ -126,7 +126,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: PlainJS.js +## General: general/PlainJS.js > Snapshot 1 @@ -169,7 +169,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Raw.js +## General: general/Raw.js > Snapshot 1 @@ -203,7 +203,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: TSLike.js +## General: general/TSLike.js > Snapshot 1 @@ -237,7 +237,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Undetected.js +## General: general/Undetected.js > Snapshot 1 diff --git a/test/lib/linter/snapshots/linter.ts.snap b/test/lib/linter/snapshots/linter.ts.snap index fdcc391c8ee5db69fe3725b552ba70010cd88341..fd113b62b90f0a033e34315aef9e0036cb138980 100644 GIT binary patch literal 8061 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 LZ=-)cf4KkvVV?9k literal 8056 zcmV-;ABW&URzV?2Rl&37 zRuTBK)E|oo00000000B+oq2p5N16A(J%?sII&JxsY`Hx?G_s``JGO%@U--5hUy0?L z5ZW^>X_8U*WV*+)90CLgEN^%*@Nz6i0trX5Kv>Qt>?YyJ@)p_t0CsqgXeLYeLNkXcYr1b?*U;wxgcn@$d@I#@ zdy*;jfMWI)9#j``$ZpUZiy9Q{R}DkyRSlt*ngJ!FCAHq+FA7Ri?vmi+65J!f0}^~w zf=4Czu>`-6;J>8d{PhmwZ*W*%jmZ0;&3nJc=6$s!t?^Lkkn60Z$4=g6CB1g?AuH*# zlRhs4qJm7`Lz3@k`(1E_;9T=4SfA52@``~9j2>M}> zUx4^skgKa8UInkIg4?U$zA6Dy<$^pNg8vRdb2Y53hC|f?B;bPVtcAU`&|eF;)WV&$ z0wm~y9IJzC>fn`iaBCfWzD|HlaY2&xpx49MdbqnD9;_E2As6Hg4RE#r{<;Ca(Ev|1 z2#{*mDDjB`99K-WSI-RQ#LnvfVfj^YJ(ca(^0^CzTwf}wsrfvwkQc}cd;YiQ!yM9- zlPOg;by?Ar)ZiIaHv5u>+^?E_dP0sXsg!(DjVoEh%1~uielwP%8wNmMAim4n_Q)=AQGtpkvjNBk+)E+gXYH_twHm)k9 z;2*w_(EuxkpJEYMW5n`crl#6A4v2TzE@5 zYxE6Oah*EYwr&{aM(5WAcTA{6$JCVRm|4C`bWAd3s+nBBC_7T>>D=fvqPdJnMBia2 z)WlGx&?T{$+})?jJ$fpo4F6x3VM=)1#Dt6M z+ocbvr_@ZlU3REx7JKD^q+OS6W)#in(KG#O!g_7^L^K+`THYW>ZjkL{SRP24eZ{qE zx@_p#Ok9=wm9(sCW@b?C(KGf-lte;J$R{&O{5sV%2L#k(kFkWIYSv68g&Fn}d4XaB!H1)LEVRJ67^sA}3 zVyMFqaWj*;CO?8Z<%lgFBgu`W0rRi#N<`Y)+AH|pYvO&1)~l9#eL)#V+M>yX(16j^ zAo4HL);6RpPMim{BbidW2h(b#?dna@NRhJ1sAe{!$qPgUmDJ*?Y(h06uKvn{Cs;4F zl+a7l%IKwsDllPK>gbYKKFeY`p%T?pLZYUZk*K#+$Wn89Id6xQm4ylA$bu3anOTM- zXDh^!g5Z^8$dGhSC_h9gDCWnkGW>X7WhKNJMxzmwqA@q2{1FZHV*bp2mgJ?NF-r1f zNUfZoANhrx>z#$1-3Pbn@ex;Xd|#~SD$aetkANBpmW*~4r)#XMIM$*?C6;l51^(F0 zQOCZ9Q)+oe^1kU@#cz|~HensdCvrHq7V}q9VXfv#DYsS=l!C1u=YX5k=d+aEyCwLb1bE%|P|JG4@zn7c^ z>NWWV>Yx-H@W728c#j7@=Yel~pxq1BV)Tc~>%Xsf;UB#4lo$LySm1**KDfsRzbT{t zf>N;24|DwRB0n7TgYJi~_`zER8^zV=zy+#Lv3Ey1=F6-xJ|D;Y1ah;?!r%*(n`51i z$}DF*@22+rWTZQj(N)U8$aeSr6EYEn&S~34qn(I$PPW}$mE(@xnD|6l-PV@uTP1k! z=&bHLoeAhCLss`<4=nRQmj~2ylhI8cc*FxUyl|lWtdsV_DKEUu3!m`9Kc1Vc7W*LX zgWD#{>Ynlf8=4cS<*HwJb4Fg#WgJDu7b|?#b45Qyd1_ z?dh2)b$3>Rw@dK8(W$$SIO^`HA$1q=K-2?!JkaNX*LvXl9+>TggXPto;e|mjyweMx z_QF4TA>xCca|ZYAlcny;jnPZ$Zq%$4^IkaW?v$hM4r$hMYur>5BdR=aU_zYZ8YEac zT9vnVlAYsfhw;d6Qf3_Pah}5R>1bWx{3CPtHYv|x|3eZyBEj#@smvK3Sm7z{wKnce z2JxG;cu5f#x!v1 z+>ciQw*c<|ZU;UFd=B_B@D1R5c{}0f!0!Q{1oaX$Nw8RgPaBLFJ{a3}yb1mFt+cr;MXKQi!# z0C<8R2VqMP`hxJWApGB;0IhdHp9;b+f>1jJqEn!I3cPCye0quio#}!;JO%z`3jEg; zXb!>V5M)DeHY7mjxS*d3!95{(I0U~7!Mtj?rWyuCkJGs>=zFW-j%xT~HT%j#i8J?yWC>+9j2_3(H-{I>|*=z_L1z@i4& z(g5)Wu>4{FX(T_`tuAQIRG2mumQRH%r^3Kg_?xNl&r=2HZWr`7Q{nehVb(NQGYwuk z4ep!9Bq}WT(T~ z=>qhKTM(ziJ=5Xg>F~^SXqf>=XFz6#06l&lyW#CK#`>uw&VFOvj}9jt!38a(zYN^Tc4Urs~ID<{ov(Wtal&hb-vc&wDV zK7YnY>hwIR{fd_CQ4LGc>RRs8bNtlZIm!Jvr$C&ZP*X9>w_Y*Lq5k{F@l*KZBvUwZ z7=`wKqd=Z-_PEKDXHPD9t$FgSMXQ*#64jfrPZq>>si~B{ThC@Rb+ABhcKr0dWvuj8 zYPxJYAHjNB=~fNXh+d!7l8!la_xMSEc#^w#@%boDTeRdR&^)z)Ipd~w;hf2(wxyU_ z>z|QLn(FXQ-7|hN`zD#pNHLifZKAO|jNsRfpWye8mEcO-xkD6N|3(~CnmXf zXXj}>l~f1p-n0_Y)A`R&scGB<&TE?F-keiRp{;_3k+^ouB$nQb^qg#hzNS+9ki#no zl*kK;m1mmZv`~3S+zowo6Z}OJyj3VzBNn{12|myScMAm@#De!U!Tn9}HKAZ*iMG!w zkvF?UUQ>y@<`Q}HO60Ya$dd(PtG?X?k2b-Nn&9V6@cSn4H4i6zf!Hzi%`ihK6e;o6 zr6uy(OXPJ3FRq*442zo~)(oA^u)P@$G{cEz=xK)Qo8jfn@cL$WYct&140j0)jg@%e zh7x(3L^=6%Gkm@o9uQveVxge_o6Yc@W_YX_o@$2w6ad>wytPYw>z|v!KNsrf4zJ{j z5|!*Lk$0d(-jyZt4vGzHnhWw=SSmEEyF?{NOXM9Zk#|CT`Rci_ZZ2#WUjCAicL)#6 zwRe1+-?uowb2~ow&n@f-{c&z?N65)qKd+Fb&l9rlaIzjB%F68!$t{Jf6D`gb(>q$6 zEvAQBoGqrB`ME77r*S*y7aEt_6*@D&P}kk_ox1*QzEfAD?9{bGcDAbqWoNtUW3sbd z^{=wCT{Ufivt6})fwNt8dV#ZD_0a{+cGY7Ga@$o7=~KgnHXR5%q~~6I*2(&E*lF(5 zVW+u~g}LTBb)8sP0K93Tz~L`BSu7H=HZ3Y-y<$|Ujo&w(Ao-HTjBq-!cSUZK}3Mpy5O55 zurmT`1a6AJtr7Tb1Xi_y-X_57Tn#?k25)bJ&$hw0&q016LZ-SPA6yC_SqfiY3QsNt z-!cI*&DF?HFN4o7gGZLZZ)1g2Su8Tm^3yA#Eth2AI78)@*>o8z8emfUI^wHgANT8=-e2+`JKP z-zY#XcR_Y-f_FSkR@4gs>x1^K}aczg#) zJ7NA#ShrJvtas^)AMS)FcS6-J2=9W8yWkzW;5)mZzDs~_cEMv^u(}Hlc7fgnw{*ed zT`+$)9N#U#x40U7W;eWQH@ts0+AQJ8)VmLG#x9)tUi!86AM_|-1>?BmdK9M&I) zqsPHK4qrbG!4t6cgaCi(NPFugJi|ms%}RN-M%-SlspQFwk{Og+4J92-DO%!G(l{e} zURK-_b>gBq1j{(ieWXIC^Q}EzRWrA#nvpaI?G3b?7oAm^buxedfTm`gE&fPbbYxK3 zKnA6qb{CCNQbY!elCr$3-wK3e5uP^GY(kg&^+YzM+Hw->k8M%n*Y#%ftd`iO8p+<# z`s%jlt1U>Kq9x>vT41%RW&7oxjNWhk%3PQOZ?2UcxmJqHRnMk7v>0aW1>g={fgvrP zR4?Y}k}^a3Z50~Qd#w$|@`Kne76~U;tkJ>~8-+wv=fzABr9ouMn<~VVtJGY8vn^RI zkt)O@u~`sx<&IOAT{^lp>1R1!fJfIxVUCH)X|&vomEq>nGUiw|8I9}x{kmq9G05ce zG9X`H1(+ZbI$9>IE5n2prAB9t3#((9yq+;)*OueOL<_@=G4f$o89ro3!-t#?OiZ`V zL3Es26*E-ROlrMG%ox<-eHmR#p0WK4ECp>3!n_#SxTp<_o>~>%Zw1S>mH2a$m;1_0 zey?Q=%%1MS(z>dQoE~+v*5*LYfEbavF)M3Bcm#e8F)MtLe{+_K zm{%^W^G%ho#Z3KBI<025Dn{N4JEf$uYP9I_1job^y$>#g1E!}kaZ2-!Vv+E{T*PBN zt>&We+Aec)BB`YG-f;VnO%mCeJf&*w@{vC4e|Mj%6;89oVzRZ_r{$tz8}>81a5Q<) zR5Iq?!9!g`mj4Y!v3>K;w(43>vbR$>9H%M$YNs4N&tbNqxXCx>L(8sn8e=y&*AA<- zQC;iqQ!V$51J;cK$pabHFuMEHgUX;yY|gHV6jfjtYG$a8?h)$9aqXb0cK4}vCEIL< zMJ~J*`>)Hrzst&Y*D~6s?9nar;6>Xw z5r@P{a?-3qF|xhLh6NL36~5zXCao^@={UsBfa=5Q( zI&B}Zn01J3UrBQ$ch1bxkmspF$r-zyvZfBm_Iwj*8@Z%?Hg0eJayvP^Et%6HJxMKL z)7^Sd8O&S%N0MfroKw85@=2QlSSG`l;nAL z9x2JjZoFW^hWjTBDSpBR!e^MKu#L=Zc|vezSI$gu?btg@;u`%DhVt1 zDRQI&t2Y&qFw4elw`3!c?e8CKm%HR^vxX@TD4J>C@2SSGbL6XC9dTmKA+zGcim5PL;hLYZ!A5(2n>*7+g&%Tg%`31@41rEHC zN5?*Ww1eZ>mh18CRe!W1p;Z$JYe~}j63oeVE)+)5E+Vng3Nqgep!}gr8rV6<<%P-I_xpr ztE=e1N8X09M&ol@9LMTpUgnnA=be*zAyW6QT%_)UdcRsWRJRCmjjmrFD@4uKX-)x3JOQ~Ux#yq|4YDEfhT}~1RWAwFTpKkg5(FK zz{e%{j0E43;6JUf;2wCX2TqGo;NADQ<-+<{SI`x>d9ef|9Xayq=RD(%Vf1eoA+aMz zUj4(Ei7j)p%3?1p^TKNHaCt2i(MXJ1box zKIi6^D|~RJ4|E^g;)6SV@H-#u&c}W)9o8c7AwPW74-fj`3BMf&gyU84_VTgbKU)QV zR|St&!P8YRH2}QKf9&$my9DuI{;3xT*?=3+X2*RhtSnt)Yk$CB>M$%zAXpX9`WdPd5{ zfwHau@xWRS9LbwUw|U?P9(YYA?LT3xDf{@07hpEbu!o{Lu@| zKG=}IE%6Q?+$&xo=Dt1TUw!a|54?U@?1wA-@M=H2SDXUfSAcvWf2Hq_&dr$qDp*zp zeO2&kaSCj9&z|Rsf3yl7tb%{fPl3Ava8jHC-S>Fh9DrK_@K*u&hXDL408K$yB~F2h z&tr@p2~KVh&ACP<9_v?MIea?JEqs2}aY zXov1S-(Y;t_^JHjWK%h_m`Y(ZJ~e*&>OvRQH8@K{6Y^PG>PuGg><_`A&~SUB>HKg{F@_+^*z(Bn1C21V0rj zDHVHnuGorShu|5Zf_dVbJl6GH)iAAkctJ6;uE)9_Y@twSVTtA}5i97ZhLu7Ets}=X z-B4W!5t@tInXWFFh99VQOv8t(9n)}1jbj?FuW?L6y~Z&O@2GJ?gnqZi2@x8s&4mbc z-n*`Lc-+)8wT1V7zSddH$Q6A?DEgwhLeXpMgrc|B4Uf+HFLj0c9B0+Tyn5JB4=3tj zK)h2dAlhC2#s-+v0BalINCOz+U1F{{p8mO0Av_hfOof+Cg_nzWh}F0tbEd)kX|QP; zTs;j2#k<2?;XeIsjSy>u{f*Gy2yYPY40DJ0Ts|ExpALtogE<}EEZ!C7x+>4VWCpa) zfITzd+8OXV@s6+t7i9NLI4~2^GvQ4$;UhE41`^#n3l7c#V-~z+7Ti6nTp&^ZuGz3} zHfXcqjkDpd*#e}|6`yU>9N0bw;&b4YbKpI5zzW{JsR_@Hgkue+t9eg#t9<`oEPonR>t(Z$5iFCztKDTW_dn! z%3*n#T%<7ULT!^5h_D=wUR|L;gxwCC&c~h!WkJW-Ss>j|X%4u$f6_+C;xeQUR75-K zg_uXScGL|uXDf`)%dc*X`%+~N_e(p|}+AG|p()8wmfv~@UA^}fE6RH#8tPGPF2f9`Y%^W&@Mqj zf>)IHU%p*}J0 Date: Fri, 19 Apr 2024 11:40:34 +0300 Subject: [PATCH 15/90] refactor: Automatically resolve BestPractices subdirs --- test/lib/linter/rules/BestPractices.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/BestPractices.ts index 391712c30..63c93ebaf 100644 --- a/test/lib/linter/rules/BestPractices.ts +++ b/test/lib/linter/rules/BestPractices.ts @@ -1,14 +1,18 @@ -import {fileURLToPath} from "node:url"; -import {runLintRulesTests} from "../_linterHelper.js"; +import { fileURLToPath } from "node:url"; +import { runLintRulesTests } from "../_linterHelper.js"; import path from "node:path"; +import { readdirSync, lstatSync } from "node:fs"; const filePath = fileURLToPath(import.meta.url); const __dirname = path.dirname(filePath); const fileName = path.basename(filePath, ".ts"); const fixturesPath = path.join(__dirname, "..", "..", "..", "fixtures", "linter", "rules", fileName); -runLintRulesTests(fileName, path.join(fixturesPath, "Negative_1")); -runLintRulesTests(fileName, path.join(fixturesPath, "Negative_2")); +const testSubDirs = readdirSync(fixturesPath); -runLintRulesTests(fileName, path.join(fixturesPath, "Positive_1")); -runLintRulesTests(fileName, path.join(fixturesPath, "Positive_2")); +for (const subDir of testSubDirs) { + const dirPath = path.join(fixturesPath, subDir); + if (!subDir.startsWith("_") && lstatSync(dirPath).isDirectory()) { + runLintRulesTests(fileName, dirPath); + } +} From badf5600f15f6eef94379b888f85e928d5dde10a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 14:01:19 +0300 Subject: [PATCH 16/90] feat: Add more tests for Best Practices --- src/linter/ui5Types/SourceFileLinter.ts | 9 +- .../BestPractices/Negative_3/Component.js | 54 ++++++++++ .../BestPractices/Negative_4/Component.js | 55 ++++++++++ .../BestPractices/Positive_3/Component.js | 53 ++++++++++ .../BestPractices/Positive_4/Component.js | 56 +++++++++++ test/lib/linter/rules/BestPractices.ts | 6 +- .../rules/snapshots/BestPractices.ts.md | 95 +++++++++++++++++- .../rules/snapshots/BestPractices.ts.snap | Bin 861 -> 952 bytes 8 files changed, 318 insertions(+), 10 deletions(-) create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_3/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_4/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_3/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_4/Component.js diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 0cfc2b73c..f4893ae6b 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -474,7 +474,7 @@ export default class SourceFileLinter { parent = parent.parent; } - if (!ts.isSourceFile(parent) || !parent.fileName.includes("Component.js") || !classDesc) { + if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("Component.js") || !classDesc) { return; } @@ -552,7 +552,7 @@ export default class SourceFileLinter { severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", message: "Use of sync loading for Component's views", - messageDetails: `https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717`, + messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}", }); } } else { @@ -562,7 +562,8 @@ export default class SourceFileLinter { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", - messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, + messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", + // messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, }); } if (routingAsyncFlag === true) { @@ -571,7 +572,7 @@ export default class SourceFileLinter { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", message: "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", - messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, + messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } } diff --git a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js new file mode 100644 index 000000000..fd669d153 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js @@ -0,0 +1,54 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + metadata: { + manifest: { + _version: "1.12.0", + + "sap.app": { + id: "com.ui5.troublesome.app", + type: "application", + i18n: "i18n/i18n.properties", + title: "{{appTitle}}", + description: "{{appDescription}}", + applicationVersion: { + version: "1.0.0", + }, + }, + + "sap.ui5": { + rootView: { + viewName: "com.ui5.troublesome.app.view.App", + type: "XML", + id: "app", + }, + + routing: { + config: { + routerClass: "sap.m.routing.Router", + viewType: "XML", + viewPath: "com.ui5.troublesome.app.view", + controlId: "app", + controlAggregation: "pages", + }, + routes: [ + { + pattern: "", + name: "main", + target: "main", + }, + ], + targets: { + main: { + viewId: "main", + viewName: "Main", + }, + }, + }, + }, + }, + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js new file mode 100644 index 000000000..cb8450969 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js @@ -0,0 +1,55 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + metadata: { + manifest: { + _version: "1.12.0", + + "sap.app": { + id: "com.ui5.troublesome.app", + type: "application", + i18n: "i18n/i18n.properties", + title: "{{appTitle}}", + description: "{{appDescription}}", + applicationVersion: { + version: "1.0.0", + }, + }, + + "sap.ui5": { + rootView: { + viewName: "com.ui5.troublesome.app.view.App", + type: "XML", + async: true, + id: "app", + }, + + routing: { + config: { + routerClass: "sap.m.routing.Router", + viewType: "XML", + viewPath: "com.ui5.troublesome.app.view", + controlId: "app", + controlAggregation: "pages", + async: true, + }, + routes: [ + { + pattern: "", + name: "main", + target: "main", + }, + ], + targets: { + main: { + viewId: "main", + viewName: "Main", + }, + }, + }, + }, + }, + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js new file mode 100644 index 000000000..29f513c90 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js @@ -0,0 +1,53 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + metadata: { + manifest: { + _version: "1.12.0", + + "sap.app": { + id: "com.ui5.troublesome.app", + type: "application", + i18n: "i18n/i18n.properties", + title: "{{appTitle}}", + description: "{{appDescription}}", + applicationVersion: { + version: "1.0.0", + }, + }, + + "sap.ui5": { + rootView: { + viewName: "com.ui5.troublesome.app.view.App", + type: "XML", + id: "app", + }, + + routing: { + config: { + routerClass: "sap.m.routing.Router", + viewType: "XML", + viewPath: "com.ui5.troublesome.app.view", + controlId: "app", + controlAggregation: "pages", + }, + routes: [ + { + pattern: "", + name: "main", + target: "main", + }, + ], + targets: { + main: { + viewId: "main", + viewName: "Main", + }, + }, + }, + }, + }, + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js new file mode 100644 index 000000000..db5f80371 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js @@ -0,0 +1,56 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("com.ui5.troublesome.app.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + metadata: { + manifest: { + _version: "1.12.0", + + "sap.app": { + id: "com.ui5.troublesome.app", + type: "application", + i18n: "i18n/i18n.properties", + title: "{{appTitle}}", + description: "{{appDescription}}", + applicationVersion: { + version: "1.0.0", + }, + }, + + "sap.ui5": { + rootView: { + viewName: "com.ui5.troublesome.app.view.App", + type: "XML", + async: true, + id: "app", + }, + + routing: { + config: { + routerClass: "sap.m.routing.Router", + viewType: "XML", + viewPath: "com.ui5.troublesome.app.view", + controlId: "app", + controlAggregation: "pages", + async: true, + }, + routes: [ + { + pattern: "", + name: "main", + target: "main", + }, + ], + targets: { + main: { + viewId: "main", + viewName: "Main", + }, + }, + }, + }, + }, + }, + }); +}); diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/BestPractices.ts index 63c93ebaf..c073945d9 100644 --- a/test/lib/linter/rules/BestPractices.ts +++ b/test/lib/linter/rules/BestPractices.ts @@ -1,7 +1,7 @@ -import { fileURLToPath } from "node:url"; -import { runLintRulesTests } from "../_linterHelper.js"; +import {fileURLToPath} from "node:url"; +import {runLintRulesTests} from "../_linterHelper.js"; import path from "node:path"; -import { readdirSync, lstatSync } from "node:fs"; +import {readdirSync, lstatSync} from "node:fs"; const filePath = fileURLToPath(import.meta.url); const __dirname = path.dirname(filePath); diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 3d34dac98..5203ae059 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -46,6 +46,36 @@ Generated by [AVA](https://avajs.dev). [] +## General: Negative_3/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [], + warningCount: 0, + }, + ] + +## General: Negative_4/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [], + warningCount: 0, + }, + ] + ## General: Positive_1/Component.js > Snapshot 1 @@ -62,7 +92,7 @@ Generated by [AVA](https://avajs.dev). fatal: undefined, line: 4, message: 'Use of sync loading for Component\'s views', - messageDetails: 'https://sapui5.hana.ondemand.com/sdk/#/topic/676b636446c94eada183b1218a824717', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717)', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, @@ -93,7 +123,7 @@ Generated by [AVA](https://avajs.dev). fatal: undefined, line: 4, message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, @@ -102,7 +132,7 @@ Generated by [AVA](https://avajs.dev). fatal: undefined, line: 4, message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', - messageDetails: 'https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, @@ -116,3 +146,62 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [] + +## General: Positive_3/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Use of sync loading for Component\'s views', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717)', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: Positive_4/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 14, + fatal: undefined, + line: 25, + message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + { + column: 15, + fatal: undefined, + line: 36, + message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 2, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 4d670a89a26d1e4183d359a4983dab955674d665..91b00ccf5a7eaaf35703c0b8ba493f7775230d86 100644 GIT binary patch literal 952 zcmV;p14sNpRzVJ~SChJ*y+VzaPGj_-W4Zo*YpAES>gsUqrkm zHdLTNWt<~6oSPF-q@#7+Q#O8;Lux@e;FgDPPFPh6WGHTO+a7&$oT50Q_Emm8ZK3i#YX0(Q8PfiQ#MwA!cO`$K`66P zP|ij{Vqg6O{0-reQjRhFJtYj6ek0%^0mOi38E}OGpE97}0B<-cmh<~qE~Wx6_&V%$ zRKnp?so8wYVLU3HNzLU#sYJ3bmzpakG!4g#?;7Fiz%@I{cSFsaQnlPbNA8I17meGO zVmr<2d;)Y`SS~{|eEs17@7e&Z9ciU|#=Vh%zSOq1Yp!};Pp(u9?^b->@v4<-?Xq{t zv$`vNud&+LYAiSE^@e|?E_jny*Os@cwdxvQtJPPltBYxhqFyLAn#18UJ-M|5HSN4r-rbD|m$gRR(M_;4T9`XTTo}xaR;rOt69ym40!6Umf5t z2bjwNFXVtPa=_DhU^AcEUignV$?La7NB4zm+rs6sodhA@^^%K&a_`9%FVfn+C&l(f zH;8m6UOFtUquGntMXLBZ5|xeEXV$f{LfQ35a4WSs+-G=KdJ`dLW;65z<+*+&d3si= zmgj2~$kzW=q(jbv8QsK2_>*p8Ss$47fmt8;82Z2iYID*hJL}W3KJ7UBwD~D3{X*8K aJ&r!DJf%F(XMNf+iS##Ubx>*@8vp>u56-Co literal 861 zcmV-j1ETyvRzVVd zW|L`mXTr`TwFeK1pcg%e2SE_@?#ZkE2=97Pyy?}mCQWL(Ra1(=58Tttyz}wS^FGfr z`!tvhwLfp}J`+~jP+WIU2_<449&yi!Dz~yJt`)s09o4lG$`X?vO3-~W@dIy_?Fmmb7*J?v;~v_Z6!KGz;<##>0#RJ>!yf#RZOcugYwu$tQ*@X;#kL1 zx}j`)D22p?e84RaPxhIW3uGwHb6ZxtGM4Izbql!rdj*WRl7TR-HK|{@0Bk5`IXP9)zDz2jSdX0^Soq4A{kh z!wk5^fX@u@oCM10RVZf@iD!HrHX_x*a6=-RZe!T)Ww#_^sZc7>S(i%0vK^SZ{e72= zaCP9CMdiDp<`t=`ZlGg#8SK5rZA!6_#C2bL$k$FagtA##wLmrNl4;G zD5fjj?#_lB9}T6lA|6$Gv~`8i&J~heGNLJBX%{=Fu+>`c(c)mW-tRF;kN^J1VBK0D z*kiCxsT1p`b>{&Aj|h0yPw%Xa^7AFVZzB5G(mJ)Je}Dl+2Fx&Eo&k3l@PPpr9pGLc z>E|f-+yP!Vz-tHioxwwI+?*y9GVj@nbZ;#!-XobGEUBOb3yZ|T5-uVYb|KHkb^N-Haror(pwQma8Z n3H`R=W7+n>OWkEpE&w2`Fr~U`N%&t2@U`N2Dz9) From 1f998ba53d781848f7077a310a6e85527ba4f79f Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 16:04:34 +0300 Subject: [PATCH 17/90] fix: Detection of unset values --- src/linter/ui5Types/SourceFileLinter.ts | 16 ++++++++++------ .../linter/rules/snapshots/BestPractices.ts.md | 14 ++------------ .../rules/snapshots/BestPractices.ts.snap | Bin 952 -> 940 bytes 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index f4893ae6b..75c69a3e0 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -504,8 +504,12 @@ export default class SourceFileLinter { manifestJson = this.extractPropsRecursive(componentManifest.initializer) ?? {}; } - let rootViewAsyncFlag: boolean | undefined; - let routingAsyncFlag: boolean | undefined; + // undefined has ambiguous meaning in that context. + // It could mean either implicit "true" or "false". + // To distinguish whether it's been set from manifest's config + // or not set at all, we'll use null. + let rootViewAsyncFlag: boolean | undefined | null = null; + let routingAsyncFlag: boolean | undefined | null = null; let rootViewAsyncFlagNode: ts.Node | undefined; let routingAsyncFlagNode: ts.Node | undefined; @@ -515,8 +519,8 @@ export default class SourceFileLinter { const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef - rootViewAsyncFlag = rootView?.async as boolean; - routingAsyncFlag = routing?.config?.async; + rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; + routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; } else { /* eslint-disable @typescript-eslint/no-explicit-any */ const instanceOfPropsRecord = (obj: any): obj is propsRecord => { @@ -546,7 +550,8 @@ export default class SourceFileLinter { } if (!hasAsyncInterface) { - if (rootViewAsyncFlag !== true || routingAsyncFlag !== true) { + if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || + routingAsyncFlag === false || routingAsyncFlag === undefined) { this.#reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, @@ -563,7 +568,6 @@ export default class SourceFileLinter { ruleId: "ui5-linter-no-sync-loading", message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", - // messageDetails: `https://sapui5.hana.ondemand.com/#/api/sap.ui.core.IAsyncContentCreation`, }); } if (routingAsyncFlag === true) { diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 5203ae059..42b5548b6 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -154,20 +154,10 @@ Generated by [AVA](https://avajs.dev). [ { coverageInfo: [], - errorCount: 1, + errorCount: 0, fatalErrorCount: 0, filePath: 'Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Use of sync loading for Component\'s views', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717)', - ruleId: 'ui5-linter-no-sync-loading', - severity: 2, - }, - ], + messages: [], warningCount: 0, }, ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 91b00ccf5a7eaaf35703c0b8ba493f7775230d86..77b3a380ac12e02b7c9bd76182e1623c569a9414 100644 GIT binary patch literal 940 zcmV;d15^A#RzV;3B&4N9K!A9$<2Y%BKvjxRq(Ukr z5Imr2vYxf4UC)@Au|pns03jhE!~^012??ovMB*R7AK-~UzzY>`h~EI-tc|m2p}^`<17A~qQ#x;i<{M8Q+K*r3FRuc zth9=EZCgA0@ttOqJN_Ph>Y<3ik4nT|1W*HTfePm-f7KYiM>M=Dm&>395P{ARy*%7h z+y(FvfNuf(2;esWWdfEd1uAUs+!CQ9Ho9C|S^}K|6+nwb*9mx(JW&2Toegzg7~T?F zD$<}bE)W~W7KAa{Z0eqJ$)g-H3(669JbrD$s!}9laf7?|=$+#fB^kBHGAeb1wY(*4 z2IlN8H%hA3!8er-aOWN1?qDo878?rq)cpkPa3v#Q2gzx5NWph6{UhK5bvvR!YV!g) z-33ycae=JP3*;0P$bAH?&jmb{0^ZP89?QeMn*S zHVP8^@^9d;2@jNVjN$JnWw`V!0rvAqYhR!nIc-Y>sxg|8#u?y1m^HE&AQ@*{2h5!ugLzc0mZ zme<7;=$dd`#&-Dl{Q=(90b1K=rF+)Do`OEtcCKr$1VK-(RV?pTLfr|fm1^y!;8Ngp zSB61jy|L3+ZPe?H@N!-7Ca-R+?o?~l4ZcyUuUFTXvlN+LEVi1%+b4Q*Z6%h<3A3W~ z${>lA^e<&=%Zk1*((R=zvBT~=)|)eN-x2<#&$GOK_``eZ-k;g$c?Dzi}qCW<`Psu2FfdN$pY%}0C13qKG?+p0B1HPXy3QAP^*#my@fImH8 zAqPB@13u3IkL7{wd}e#$KQc*Pc}sM3U-+&qe4dPxDCYaK;+dvYx>TDy0o*uCgS zMt72>!{$2PcoF+Zl~5Z|*-GZjrdCcUw`l}-Qmdoq4DZTdBE-zb3_V17t{qFBo|CE- zgjz+i^?w!V2rrn?No<5aKZ%|45BW(avALPg&HNJ~SChJ*y+VzaPGj_-W4Zo*YpAES>gsUqrkm zHdLTNWt<~6oSPF-q@#7+Q#O8;Lux@e;FgDPPFPh6WGHTO+a7&$oT50Q_Emm8ZK3i#YX0(Q8PfiQ#MwA!cO`$K`66P zP|ij{Vqg6O{0-reQjRhFJtYj6ek0%^0mOi38E}OGpE97}0B<-cmh<~qE~Wx6_&V%$ zRKnp?so8wYVLU3HNzLU#sYJ3bmzpakG!4g#?;7Fiz%@I{cSFsaQnlPbNA8I17meGO zVmr<2d;)Y`SS~{|eEs17@7e&Z9ciU|#=Vh%zSOq1Yp!};Pp(u9?^b->@v4<-?Xq{t zv$`vNud&+LYAiSE^@e|?E_jny*Os@cwdxvQtJPPltBYxhqFyLAn#18UJ-M|5HSN4r-rbD|m$gRR(M_;4T9`XTTo}xaR;rOt69ym40!6Umf5t z2bjwNFXVtPa=_DhU^AcEUignV$?La7NB4zm+rs6sodhA@^^%K&a_`9%FVfn+C&l(f zH;8m6UOFtUquGntMXLBZ5|xeEXV$f{LfQ35a4WSs+-G=KdJ`dLW;65z<+*+&d3si= zmgj2~$kzW=q(jbv8QsK2_>*p8Ss$47fmt8;82Z2iYID*hJL}W3KJ7UBwD~D3{X*8K aJ&r!DJf%F(XMNf+iS##Ubx>*@8vp>u56-Co From acd3472d4af055c88ba458d4bd53d1977afe9810 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 16:08:55 +0300 Subject: [PATCH 18/90] refactor: Improve messaging --- src/linter/ui5Types/SourceFileLinter.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 75c69a3e0..2a2f632de 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -556,8 +556,10 @@ export default class SourceFileLinter { node: classDesc, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", - message: "Use of sync loading for Component's views", - messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}", + message: "Root View and Routing are not configured to load targets asynchronously", + messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", }); } } else { From 89b12619ebe4a51c5a7f9ec1a1ace0c6dde1a05e Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 16:11:45 +0300 Subject: [PATCH 19/90] fix: Eslint --- src/linter/ui5Types/SourceFileLinter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 2a2f632de..fcc9a34e3 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -558,8 +558,8 @@ export default class SourceFileLinter { ruleId: "ui5-linter-no-sync-loading", message: "Root View and Routing are not configured to load targets asynchronously", messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + - "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", }); } } else { From 1611ad9e0995a14c439b210f1f8ca401ef9256ca Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 19 Apr 2024 16:13:01 +0300 Subject: [PATCH 20/90] fix: Update snapshots --- .../linter/rules/snapshots/BestPractices.ts.md | 4 ++-- .../rules/snapshots/BestPractices.ts.snap | Bin 940 -> 1010 bytes 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 42b5548b6..ade375e64 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -91,8 +91,8 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Use of sync loading for Component\'s views', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717)', + message: 'Root View and Routing are not configured to load targets asynchronously', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 77b3a380ac12e02b7c9bd76182e1623c569a9414..25da04e6805055d0275f267105369735db8f0fab 100644 GIT binary patch literal 1010 zcmV8I5*5N(-`2*pki^YfRhET%r_$qrxG`N$y;!Zi((5<#sLb=ji zE3M*f+tki}e7|1jj=xWz_{gLCqXK!a0jL1DK)Lgjy=DyGCmK8zi$%~Jh(KqE-WY7k z?*aG-z&8MX1n@h6A^}U(ca+=Oxhq0P-ofL-!UE_VC1?QXh2agc zsUi(3;sSXC+ng{)n+@GjE_szf>Vsm$9gp7{^Hm{|vAD%u^C0FhL`g=?p^OSGVJ&Y6 zn{sn@j~gXbV>D7>1Ur8OyHQ(a$TlGG;^PQxaU~;RyUA&Fh{5+RJtFXlyd6;>m05wD z?gFVyxji+>z{MR+2WLkNFMeS{0Y5%7=z@_-jT;ED%)=K(+aNP>=_oIQkcK9zVb)N!Y! z`WQZwvSt$ulU4p)%9e?x68(Ldlr7(fX|TSrt+iwCO0mbdssDkn_DL&2nC!?ne-!*mdigf{hICG|8qDi_Q9A`9epoF2_k? z%StbI<1fcOfYRMz#jY^Y?e}^14xb-})MYB?hXeoP4wzZ}^vBP{>NU0TGog5qH%`6$ zFA4aXfCu9g%u7)Ip{HPHi2m%V7bRkL*#pWRu;l^wJm6Cg_`?G}@PY6Bqs6R1g0OaD?W5jLxBj5JBcod*{e3J6Br#r? zj+8>)mcdvTOVg4WdW!U1KNdZs%KZN%>4;e{rMu*T|JhyglwU>0-6dzkd^XHaa+uFg gI4z!^4fB6vm=`Cc=cU;&KOvI-2JBMuX#^So0L@SFaR2}S literal 940 zcmV;d15^A#RzV;3B&4N9K!A9$<2Y%BKvjxRq(Ukr z5Imr2vYxf4UC)@Au|pns03jhE!~^012??ovMB*R7AK-~UzzY>`h~EI-tc|m2p}^`<17A~qQ#x;i<{M8Q+K*r3FRuc zth9=EZCgA0@ttOqJN_Ph>Y<3ik4nT|1W*HTfePm-f7KYiM>M=Dm&>395P{ARy*%7h z+y(FvfNuf(2;esWWdfEd1uAUs+!CQ9Ho9C|S^}K|6+nwb*9mx(JW&2Toegzg7~T?F zD$<}bE)W~W7KAa{Z0eqJ$)g-H3(669JbrD$s!}9laf7?|=$+#fB^kBHGAeb1wY(*4 z2IlN8H%hA3!8er-aOWN1?qDo878?rq)cpkPa3v#Q2gzx5NWph6{UhK5bvvR!YV!g) z-33ycae=JP3*;0P$bAH?&jmb{0^ZP89?QeMn*S zHVP8^@^9d;2@jNVjN$JnWw`V!0rvAqYhR!nIc-Y>sxg|8#u?y1m^HE&AQ@*{2h5!ugLzc0mZ zme<7;=$dd`#&-Dl{Q=(90b1K=rF+)Do`OEtcCKr$1VK-(RV?pTLfr|fm1^y!;8Ngp zSB61jy|L3+ZPe?H@N!-7Ca-R+?o?~l4ZcyUuUFTXvlN+LEVi1%+b4Q*Z6%h<3A3W~ z${>lA^e<&=%Zk1*((R=zvBT~=)|)eN-x2<#&$GOK_``eZ-k;g$c?Dzi}qCW<`Psu2FfdN$pY%}0C13qKG?+p0B1HPXy3QAP^*#my@fImH8 zAqPB@13u3IkL7{wd}e#$KQc*Pc}sM3U-+&qe4dPxDCYaK;+dvYx>TDy0o*uCgS zMt72>!{$2PcoF+Zl~5Z|*-GZjrdCcUw`l}-Qmdoq4DZTdBE-zb3_V17t{qFBo|CE- zgjz+i^?w!V2rrn?No<5aKZ%|45BW(avALPg&HN Date: Mon, 22 Apr 2024 10:28:01 +0300 Subject: [PATCH 21/90] refactor: Interfaces are part of metadata --- src/linter/ui5Types/SourceFileLinter.ts | 94 ++++++++++--------- .../BestPractices/Negative_1/Component.js | 2 +- .../BestPractices/Negative_3/Component.js | 2 +- .../BestPractices/Positive_2/Component.js | 2 +- .../BestPractices/Positive_4/Component.js | 2 +- 5 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index fcc9a34e3..fc2fb00a6 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -478,32 +478,37 @@ export default class SourceFileLinter { return; } - let classInterfaces: ts.ClassElement | undefined; - let componentManifest: ts.ClassElement | undefined; + let classInterfaces: ts.ObjectLiteralElementLike | undefined; + let componentManifest: ts.ObjectLiteralElementLike | undefined; + let metadata: ts.ClassElement | undefined; if (ts.isClassDeclaration(classDesc)) { classDesc.members.forEach((classMember) => { - if (classMember.name?.getText() === "interfaces") { - classInterfaces = classMember; - } else if (classMember.name?.getText() === "metadata") { - componentManifest = classMember; + if (classMember.name?.getText() === "metadata") { + metadata = classMember; + } + }); + } + + if (metadata && ts.isPropertyDeclaration(metadata) && + metadata.initializer && ts.isObjectLiteralExpression(metadata.initializer)) { + metadata.initializer.properties.forEach((prop) => { + if (prop.name?.getText() === "interfaces") { + classInterfaces = prop; + } + if (prop.name?.getText() === "manifest") { + componentManifest = prop; } }); } let hasAsyncInterface = false; - if (classInterfaces && ts.isPropertyDeclaration(classInterfaces) && + if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { hasAsyncInterface = classInterfaces.initializer .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); } - let manifestJson: propsRecord = {}; - if (componentManifest && ts.isPropertyDeclaration(componentManifest) && - componentManifest.initializer && ts.isObjectLiteralExpression(componentManifest.initializer)) { - manifestJson = this.extractPropsRecursive(componentManifest.initializer) ?? {}; - } - // undefined has ambiguous meaning in that context. // It could mean either implicit "true" or "false". // To distinguish whether it's been set from manifest's config @@ -513,39 +518,42 @@ export default class SourceFileLinter { let rootViewAsyncFlagNode: ts.Node | undefined; let routingAsyncFlagNode: ts.Node | undefined; - if (manifestJson.manifest?.value === "\"json\"") { // The manifest is an external manifest.json file - const parsedManifestContent = - JSON.parse(this.#manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; + if (componentManifest && ts.isPropertyAssignment(componentManifest)) { + // The manifest is an external manifest.json file + if (componentManifest.initializer.getText() === "\"json\"") { + const parsedManifestContent = + JSON.parse(this.#manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; + + const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; + // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef + rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; + routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; + } else if (ts.isObjectLiteralExpression(componentManifest.initializer)) { + /* eslint-disable @typescript-eslint/no-explicit-any */ + const instanceOfPropsRecord = (obj: any): obj is propsRecord => { + return !!obj && typeof obj === "object"; + }; - const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; - // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef - rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; - routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; - } else { - /* eslint-disable @typescript-eslint/no-explicit-any */ - const instanceOfPropsRecord = (obj: any): obj is propsRecord => { - return !!obj && typeof obj === "object"; - }; - - let manifestSapui5Section: propsRecord | undefined; - if (instanceOfPropsRecord(manifestJson.manifest?.value) && - instanceOfPropsRecord(manifestJson.manifest.value["\"sap.ui5\""].value)) { - manifestSapui5Section = manifestJson.manifest.value["\"sap.ui5\""].value; - } + const manifestJson = this.extractPropsRecursive(componentManifest.initializer) ?? {}; + let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; + if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { + manifestSapui5Section = manifestJson["\"sap.ui5\""].value; + } - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && - typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { - rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; - rootViewAsyncFlagNode = manifestSapui5Section?.rootView?.value.async?.node; - } + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && + typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { + rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; + rootViewAsyncFlagNode = manifestSapui5Section?.rootView?.value.async?.node; + } - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && - typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { - routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; - routingAsyncFlagNode = manifestSapui5Section?.routing?.value.config?.value.async?.node; + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && + typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { + routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; + routingAsyncFlagNode = manifestSapui5Section?.routing?.value.config?.value.async?.node; + } } } diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js index a444897d9..2be38d9a8 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js @@ -2,8 +2,8 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: "json", }, }); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js index fd669d153..e0b7edbc3 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js @@ -2,8 +2,8 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: { _version: "1.12.0", diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js index a444897d9..2be38d9a8 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js @@ -2,8 +2,8 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: "json", }, }); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js index db5f80371..7b2e60096 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js @@ -2,8 +2,8 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; return UIComponent.extend("com.ui5.troublesome.app.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: { _version: "1.12.0", From 894029c2f39b5a21073b68d7f35d330657d5aa72 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 24 Apr 2024 09:40:07 +0300 Subject: [PATCH 22/90] refactor: Look into hierarchy --- src/linter/ui5Types/BestPractices.ts | 280 ++++++++++++++++++ src/linter/ui5Types/SourceFileLinter.ts | 187 +----------- .../rules/snapshots/BestPractices.ts.md | 8 +- .../rules/snapshots/BestPractices.ts.snap | Bin 1010 -> 996 bytes 4 files changed, 291 insertions(+), 184 deletions(-) create mode 100644 src/linter/ui5Types/BestPractices.ts diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts new file mode 100644 index 000000000..1f394adbe --- /dev/null +++ b/src/linter/ui5Types/BestPractices.ts @@ -0,0 +1,280 @@ +import ts from "typescript"; +import SourceFileReporter from "./SourceFileReporter.js"; +import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.d.ts"; +import {LintMessageSeverity} from "../LinterContext.js"; + +type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; +type propsRecord = Record; + +interface AsyncInterfaceFindType { + hasAsyncInterface: boolean | undefined | null; + routingAsyncFlag: boolean | undefined | null; + rootViewAsyncFlag: boolean | undefined | null; +} + +export default function analyzeComponentJson( + node: ts.ExpressionWithTypeArguments, + manifestContent: string | undefined, + reporter: SourceFileReporter, + checker: ts.TypeChecker +) { + let parent = node.parent; + let classDesc; + while (!parent || parent.kind !== ts.SyntaxKind.SourceFile) { + if (parent.kind === ts.SyntaxKind.ClassDeclaration) { + classDesc = parent; + } + parent = parent.parent; + } + + if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("Component.js") || !classDesc) { + return; + } + + // const expectedUIComponentsList = { + // "sap/ui/core/UIComponent": "UIComponent", + // "sap/ui/generic/app/AppComponent": "AppComponent", + // "sap/suite/ui/generic/template/lib/AppComponent": "AppComponent", + // "sap/fe/core/AppComponent": "AppComponent", + // }; + + if (classDesc && ts.isClassDeclaration(classDesc)) { + const analysisResult = findAsyncInterface(classDesc, manifestContent, checker); + + if (analysisResult) { + reportResults(analysisResult, reporter, classDesc); + } + } +} + +function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): AsyncInterfaceFindType { + // null = parent property does not exist i.e. rootView + // undefined = async flag is missing + // true|false = async flag is explicitly set + + const compareValues = (aProp: null | undefined | boolean, + bProp: null | undefined | boolean): null | undefined | boolean => { + let result = null; + if (aProp === undefined || bProp === undefined) { + result = undefined; + } + if (typeof aProp === "boolean" || typeof bProp === "boolean") { + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + result = aProp || bProp; + } + + return result; + }; + + return { + routingAsyncFlag: compareValues(a.routingAsyncFlag, b.routingAsyncFlag), + rootViewAsyncFlag: compareValues(a.rootViewAsyncFlag, b.rootViewAsyncFlag), + hasAsyncInterface: compareValues(a.hasAsyncInterface, b.hasAsyncInterface), + }; +} + +function findAsyncInterface( + classDefinition: ts.ClassDeclaration, + manifestContent: string | undefined, + checker: ts.TypeChecker +): AsyncInterfaceFindType | undefined { + if (ts.isClassDeclaration(classDefinition)) { + const returnTypeTemplate = { + hasAsyncInterface: null, + routingAsyncFlag: null, + rootViewAsyncFlag: null, + } as AsyncInterfaceFindType; + + // Checks the interfaces and manifest + const curClassAnalysis = classDefinition.members.reduce((acc, member) => { + const checkResult = doChecks(member as ts.PropertyDeclaration, manifestContent); + return mergeResults(acc, checkResult); + }, {...returnTypeTemplate}); + + const heritageAnalysis = + classDefinition?.heritageClauses?.flatMap((parentClasses: ts.HeritageClause) => { + return parentClasses.types.flatMap((parentClass) => { + const parentClassType = checker.getTypeAtLocation(parentClass); + + return parentClassType.symbol?.declarations?.flatMap((declaration) => { + let result = {...returnTypeTemplate} as AsyncInterfaceFindType; + // Continue down the heritage chain to search for + // the async interface or manifest flags + if (ts.isClassDeclaration(declaration) && + declaration?.name?.getText() !== "UIComponent") { + result = findAsyncInterface(declaration, manifestContent, checker) ?? result; + } + + return result; + }); + }); + }) ?? []; + + return [...heritageAnalysis, curClassAnalysis].reduce((acc, curAnalysis) => { + return mergeResults(acc ?? {...returnTypeTemplate}, curAnalysis ?? {...returnTypeTemplate}); + }); + } +} + +function doChecks(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { + let classInterfaces: ts.ObjectLiteralElementLike | undefined; + let componentManifest: ts.ObjectLiteralElementLike | undefined; + + if (metadata && ts.isPropertyDeclaration(metadata) && + metadata.initializer && ts.isObjectLiteralExpression(metadata.initializer)) { + metadata.initializer.properties.forEach((prop) => { + if (prop.name?.getText() === "interfaces") { + classInterfaces = prop; + } + if (prop.name?.getText() === "manifest") { + componentManifest = prop; + } + }); + } + + let hasAsyncInterface = false; + if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && + classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { + hasAsyncInterface = classInterfaces.initializer + .elements.some((implementedInterface) => + implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); + } + + // undefined has ambiguous meaning in that context. + // It could mean either implicit "true" or "false". + // To distinguish whether it's been set from manifest's config + // or not set at all, we'll use null. + let rootViewAsyncFlag: boolean | undefined | null = null; + let routingAsyncFlag: boolean | undefined | null = null; + + if (componentManifest && ts.isPropertyAssignment(componentManifest)) { + // The manifest is an external manifest.json file + if (componentManifest.initializer.getText() === "\"json\"") { + const parsedManifestContent = + JSON.parse(manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; + + const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; + // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef + rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; + routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; + } else if (ts.isObjectLiteralExpression(componentManifest.initializer)) { + /* eslint-disable @typescript-eslint/no-explicit-any */ + const instanceOfPropsRecord = (obj: any): obj is propsRecord => { + return !!obj && typeof obj === "object"; + }; + + const manifestJson = extractPropsRecursive(componentManifest.initializer) ?? {}; + let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; + if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { + manifestSapui5Section = manifestJson["\"sap.ui5\""].value; + } + + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && + typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { + rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; + } + + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && + typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { + routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; + } + } + } + + return { + routingAsyncFlag, + rootViewAsyncFlag, + hasAsyncInterface, + }; +} + +function extractPropsRecursive(node: ts.ObjectLiteralExpression) { + const properties = Object.create(null) as propsRecord; + + node.properties?.forEach((prop) => { + if (!ts.isPropertyAssignment(prop) || !prop.name) { + return; + } + + const key = prop.name.getText(); + if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) { + properties[key] = {value: true, node: prop.initializer}; + } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { + properties[key] = {value: false, node: prop.initializer}; + } else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) { + properties[key] = {value: null, node: prop.initializer}; + } else if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { + properties[key] = {value: extractPropsRecursive(prop.initializer), node: prop.initializer}; + } else if (ts.isArrayLiteralExpression(prop.initializer)) { + const resolvedValue = prop.initializer.elements.map((elem) => { + if (!ts.isObjectLiteralExpression(elem)) { + return; + } + return extractPropsRecursive(elem); + }).filter(($) => $) as propsRecordValueType[]; + + properties[key] = {value: resolvedValue, node: prop.initializer}; + } else if ( + (ts.isIdentifier(prop.initializer) || + ts.isNumericLiteral(prop.initializer) || + ts.isStringLiteral(prop.initializer)) && + + prop.initializer.getText()) { + properties[key] = {value: prop.initializer.getText(), node: prop.initializer}; + } else { + // throw new Error("Unhandled property assignment"); + } + }); + return properties; +} + +function reportResults( + analysisResult: AsyncInterfaceFindType, + reporter: SourceFileReporter, + classDesc: ts.ClassDeclaration +) { + let hasAsyncInterface: null | undefined | boolean = null; + let routingAsyncFlag: null | undefined | boolean = null; + let rootViewAsyncFlag: null | undefined | boolean = null; + ({hasAsyncInterface, routingAsyncFlag, rootViewAsyncFlag} = analysisResult); + + if (!hasAsyncInterface) { + if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || + routingAsyncFlag === false || routingAsyncFlag === undefined) { + reporter.addMessage({ + node: classDesc, + severity: LintMessageSeverity.Error, + ruleId: "ui5-linter-no-sync-loading", + message: "Root View and Routing are not configured to load targets asynchronously", + messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", + }); + } + } else { + if (rootViewAsyncFlag === true) { + reporter.addMessage({ + node: classDesc, + severity: LintMessageSeverity.Warning, + ruleId: "ui5-linter-no-sync-loading", + message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", + messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", + }); + } + if (routingAsyncFlag === true) { + reporter.addMessage({ + node: classDesc, + severity: LintMessageSeverity.Warning, + ruleId: "ui5-linter-no-sync-loading", + message: "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", + messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", + }); + } + } +} diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index fc2fb00a6..a59c8972b 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -1,19 +1,13 @@ import ts, {Identifier} from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; import LinterContext, {ResourcePath, CoverageCategory, LintMessageSeverity} from "../LinterContext.js"; -import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.d.ts"; +import analyzeComponentJson from "./BestPractices.js"; interface DeprecationInfo { symbol: ts.Symbol; messageDetails?: string; } -type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; -type propsRecord = Record; - export default class SourceFileLinter { #resourcePath: ResourcePath; #sourceFile: ts.SourceFile; @@ -77,7 +71,12 @@ export default class SourceFileLinter { } else if (node.kind === ts.SyntaxKind.ImportDeclaration) { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { - this.analyzeComponentJson(node as ts.ExpressionWithTypeArguments); + analyzeComponentJson( + node as ts.ExpressionWithTypeArguments, + this.#manifestContent, + this.#reporter, + this.#checker + ); } // Traverse the whole AST from top to bottom @@ -460,178 +459,6 @@ export default class SourceFileLinter { } } - analyzeComponentJson(node: ts.ExpressionWithTypeArguments) { - if (node.expression.getText() !== "UIComponent") { - return; - } - - let parent = node.parent; - let classDesc; - while (!parent || parent.kind !== ts.SyntaxKind.SourceFile) { - if (parent.kind === ts.SyntaxKind.ClassDeclaration) { - classDesc = parent; - } - parent = parent.parent; - } - - if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("Component.js") || !classDesc) { - return; - } - - let classInterfaces: ts.ObjectLiteralElementLike | undefined; - let componentManifest: ts.ObjectLiteralElementLike | undefined; - let metadata: ts.ClassElement | undefined; - if (ts.isClassDeclaration(classDesc)) { - classDesc.members.forEach((classMember) => { - if (classMember.name?.getText() === "metadata") { - metadata = classMember; - } - }); - } - - if (metadata && ts.isPropertyDeclaration(metadata) && - metadata.initializer && ts.isObjectLiteralExpression(metadata.initializer)) { - metadata.initializer.properties.forEach((prop) => { - if (prop.name?.getText() === "interfaces") { - classInterfaces = prop; - } - if (prop.name?.getText() === "manifest") { - componentManifest = prop; - } - }); - } - - let hasAsyncInterface = false; - if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && - classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { - hasAsyncInterface = classInterfaces.initializer - .elements.some((implementedInterface) => - implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); - } - - // undefined has ambiguous meaning in that context. - // It could mean either implicit "true" or "false". - // To distinguish whether it's been set from manifest's config - // or not set at all, we'll use null. - let rootViewAsyncFlag: boolean | undefined | null = null; - let routingAsyncFlag: boolean | undefined | null = null; - let rootViewAsyncFlagNode: ts.Node | undefined; - let routingAsyncFlagNode: ts.Node | undefined; - - if (componentManifest && ts.isPropertyAssignment(componentManifest)) { - // The manifest is an external manifest.json file - if (componentManifest.initializer.getText() === "\"json\"") { - const parsedManifestContent = - JSON.parse(this.#manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; - - const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; - // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef - rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; - routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; - } else if (ts.isObjectLiteralExpression(componentManifest.initializer)) { - /* eslint-disable @typescript-eslint/no-explicit-any */ - const instanceOfPropsRecord = (obj: any): obj is propsRecord => { - return !!obj && typeof obj === "object"; - }; - - const manifestJson = this.extractPropsRecursive(componentManifest.initializer) ?? {}; - let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; - if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { - manifestSapui5Section = manifestJson["\"sap.ui5\""].value; - } - - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && - typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { - rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; - rootViewAsyncFlagNode = manifestSapui5Section?.rootView?.value.async?.node; - } - - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && - typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { - routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; - routingAsyncFlagNode = manifestSapui5Section?.routing?.value.config?.value.async?.node; - } - } - } - - if (!hasAsyncInterface) { - if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || - routingAsyncFlag === false || routingAsyncFlag === undefined) { - this.#reporter.addMessage({ - node: classDesc, - severity: LintMessageSeverity.Error, - ruleId: "ui5-linter-no-sync-loading", - message: "Root View and Routing are not configured to load targets asynchronously", - messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + - "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", - }); - } - } else { - if (rootViewAsyncFlag === true) { - this.#reporter.addMessage({ - node: rootViewAsyncFlagNode ?? classDesc, - severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", - messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", - }); - } - if (routingAsyncFlag === true) { - this.#reporter.addMessage({ - node: routingAsyncFlagNode ?? classDesc, - severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", - messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", - }); - } - } - } - - extractPropsRecursive = (node: ts.ObjectLiteralExpression) => { - const properties = Object.create(null) as propsRecord; - - node.properties?.forEach((prop) => { - if (!ts.isPropertyAssignment(prop) || !prop.name) { - return; - } - - const key = prop.name.getText(); - if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) { - properties[key] = {value: true, node: prop.initializer}; - } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { - properties[key] = {value: false, node: prop.initializer}; - } else if (prop.initializer.kind === ts.SyntaxKind.NullKeyword) { - properties[key] = {value: null, node: prop.initializer}; - } else if (ts.isObjectLiteralExpression(prop.initializer) && prop.initializer.properties) { - properties[key] = {value: this.extractPropsRecursive(prop.initializer), node: prop.initializer}; - } else if (ts.isArrayLiteralExpression(prop.initializer)) { - const resolvedValue = prop.initializer.elements.map((elem) => { - if (!ts.isObjectLiteralExpression(elem)) { - return; - } - return this.extractPropsRecursive(elem); - }).filter(($) => $) as propsRecordValueType[]; - - properties[key] = {value: resolvedValue, node: prop.initializer}; - } else if ( - (ts.isIdentifier(prop.initializer) || - ts.isNumericLiteral(prop.initializer) || - ts.isStringLiteral(prop.initializer)) && - - prop.initializer.getText()) { - properties[key] = {value: prop.initializer.getText(), node: prop.initializer}; - } else { - // throw new Error("Unhandled property assignment"); - } - }); - return properties; - }; - isSymbolOfUi5Type(symbol: ts.Symbol) { if (symbol.name.startsWith("sap/")) { return true; diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index ade375e64..24ab15d98 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -174,18 +174,18 @@ Generated by [AVA](https://avajs.dev). filePath: 'Component.js', messages: [ { - column: 14, + column: 9, fatal: undefined, - line: 25, + line: 4, message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, { - column: 15, + column: 9, fatal: undefined, - line: 36, + line: 4, message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 25da04e6805055d0275f267105369735db8f0fab..9407db35a680a9660ad6a3e7b8f858167698e9b8 100644 GIT binary patch literal 996 zcmVhT+s?;{tSC90UZ=Sb>{<7YJ6hxOhk znSJSb>mQ2<00000000B+SI=)7MHK$tu78pKaH=8>NJ!IELIj8xJC2i92&qa@6{(Oa z5(rLcvYxf4UC)@AaY7CpkdTlN;($0HAtBl$68{0*5hwluE>zqQe*^5=PVG$_M-f)* zVxM;Q?Y#H=eeZp5=5Dkb>+p{K;+}BQ#o{A&LnvW*e3iW|THMJ!@j*4%)Sa$YLb=Lq zE3M*P+t$v0a<|#!j=xWz`Y0m#QHi`)0n`9oq{0QtUo(au5DlNogyAi* zr6LU~<05%O+k!Agn@!zQE`60l=7Vy?9gp9f@Kq_2vAD%u`!MDxL}^Ctk&H?mVJ&Y7 zn{jh?pBp7rYdlhE3_E`eyK!4?#5N@G(!&Vsa3v#QljO8I!r*(C9}xIR-i|4d+Ppw! zyFhAFE|ArEfy_{WJcPjdoWPkR@RqjnL^C{h=|3g#X8`vBEE4eYNeO)Gv;-!pOou@^ z9R|t!@?Xba6CO$B2*Tgd0O8W_1l%WpJm3WnxZ(ldd%!O~(x77~=Z~OV%p_h2b=>Qy z0fx_HtoanfbX7c;vE^c^#9&`8V=E3|8m@2bXzkd$QtUIXnruh+oK!8wjbKVU7HSpA zR?mngbDG7PH<{z6C7fm49;mQww9-8rA7sLuAB4Fs9G9^jy!JrvSi!E1>|{4JZzd66 zYCG4pSA(D@*D98GE1~WL)k?MYT5vgVx+}w=vEJBitTyWPMtG$zc#~H*R(Gql>IUDa z)z_=*%N4fO>BgcXlw*mDo~(r0h{{$PaZ@WNl-o3dJE;|u$_W$kP%x?3Xl*fVm=&)7 z4_OrRmSvGPY^m>aEiiqQf<8J+DRLu5?Gikf61T1`*x2ySl5Bdh*lG@!&-dioN}MLP zqV!4k%_9QvPhz|8B%KYmWFUQ-)CrxY*pCaIVI z6#?H6aBq@=c`3?2_7&_5(O-#rQ7UGyctF(ywmsmE2YluMe|o@&KJbHoyqJ}!^s5j2 z<^zBGz(NjqF$a8}1D?wR+xg7)!V{u}Z|sPU-Vkqp-GP*O?-zSnl5|f4L zSSjRP8BBDsJS~}_$4Jlh6VWrS%>Pf4j+q5hx=SAVpWh{C{38I5*5N(-`2*pki^YfRhET%r_$qrxG`N$y;!Zi((5<#sLb=ji zE3M*f+tki}e7|1jj=xWz_{gLCqXK!a0jL1DK)Lgjy=DyGCmK8zi$%~Jh(KqE-WY7k z?*aG-z&8MX1n@h6A^}U(ca+=Oxhq0P-ofL-!UE_VC1?QXh2agc zsUi(3;sSXC+ng{)n+@GjE_szf>Vsm$9gp7{^Hm{|vAD%u^C0FhL`g=?p^OSGVJ&Y6 zn{sn@j~gXbV>D7>1Ur8OyHQ(a$TlGG;^PQxaU~;RyUA&Fh{5+RJtFXlyd6;>m05wD z?gFVyxji+>z{MR+2WLkNFMeS{0Y5%7=z@_-jT;ED%)=K(+aNP>=_oIQkcK9zVb)N!Y! z`WQZwvSt$ulU4p)%9e?x68(Ldlr7(fX|TSrt+iwCO0mbdssDkn_DL&2nC!?ne-!*mdigf{hICG|8qDi_Q9A`9epoF2_k? z%StbI<1fcOfYRMz#jY^Y?e}^14xb-})MYB?hXeoP4wzZ}^vBP{>NU0TGog5qH%`6$ zFA4aXfCu9g%u7)Ip{HPHi2m%V7bRkL*#pWRu;l^wJm6Cg_`?G}@PY6Bqs6R1g0OaD?W5jLxBj5JBcod*{e3J6Br#r? zj+8>)mcdvTOVg4WdW!U1KNdZs%KZN%>4;e{rMu*T|JhyglwU>0-6dzkd^XHaa+uFg gI4z!^4fB6vm=`Cc=cU;&KOvI-2JBMuX#^So0L@SFaR2}S From b88f623647117211d237417a5ba9e3e6e92eb309 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 24 Apr 2024 15:51:01 +0300 Subject: [PATCH 23/90] fix: Extract and check against real module dependency var --- src/linter/ui5Types/BestPractices.ts | 34 +++++++++++++++++++--------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 1f394adbe..adcfbae29 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -15,6 +15,13 @@ interface AsyncInterfaceFindType { rootViewAsyncFlag: boolean | undefined | null; } +const expectedUIComponentsList = [ + "sap/ui/core/UIComponent", + "sap/ui/generic/app/AppComponent", + "sap/suite/ui/generic/template/lib/AppComponent", + "sap/fe/core/AppComponent", +]; + export default function analyzeComponentJson( node: ts.ExpressionWithTypeArguments, manifestContent: string | undefined, @@ -34,15 +41,18 @@ export default function analyzeComponentJson( return; } - // const expectedUIComponentsList = { - // "sap/ui/core/UIComponent": "UIComponent", - // "sap/ui/generic/app/AppComponent": "AppComponent", - // "sap/suite/ui/generic/template/lib/AppComponent": "AppComponent", - // "sap/fe/core/AppComponent": "AppComponent", - // }; + // Gets module dependency's var name + // @ts-expect-error: imports is part of the sourceFile, but is not defined in types + const importsList = parent.imports as ts.Node[]; + const uiComponentImportStatement = importsList.find((importStatement) => + expectedUIComponentsList.includes(importStatement.getText())); + let uiComponentImportVar = "UIComponent"; + if (uiComponentImportStatement && ts.isImportDeclaration(uiComponentImportStatement.parent)) { + uiComponentImportVar = uiComponentImportStatement.parent.importClause?.name?.getText() ?? uiComponentImportVar; + } if (classDesc && ts.isClassDeclaration(classDesc)) { - const analysisResult = findAsyncInterface(classDesc, manifestContent, checker); + const analysisResult = findAsyncInterface(classDesc, manifestContent, checker, uiComponentImportVar); if (analysisResult) { reportResults(analysisResult, reporter, classDesc); @@ -79,7 +89,8 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy function findAsyncInterface( classDefinition: ts.ClassDeclaration, manifestContent: string | undefined, - checker: ts.TypeChecker + checker: ts.TypeChecker, + uiComponentImportVar = "UIComponent" ): AsyncInterfaceFindType | undefined { if (ts.isClassDeclaration(classDefinition)) { const returnTypeTemplate = { @@ -104,7 +115,7 @@ function findAsyncInterface( // Continue down the heritage chain to search for // the async interface or manifest flags if (ts.isClassDeclaration(declaration) && - declaration?.name?.getText() !== "UIComponent") { + declaration?.name?.getText() !== uiComponentImportVar) { result = findAsyncInterface(declaration, manifestContent, checker) ?? result; } @@ -135,7 +146,7 @@ function doChecks(metadata: ts.PropertyDeclaration, manifestContent: string | un }); } - let hasAsyncInterface = false; + let hasAsyncInterface = null; if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { hasAsyncInterface = classInterfaces.initializer @@ -246,7 +257,8 @@ function reportResults( if (!hasAsyncInterface) { if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || - routingAsyncFlag === false || routingAsyncFlag === undefined) { + routingAsyncFlag === false || routingAsyncFlag === undefined || + (hasAsyncInterface === null && rootViewAsyncFlag === null && routingAsyncFlag === null)) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, From aedea65dc04e6f2cd9d906fead0ad11af9173327 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 10:17:11 +0300 Subject: [PATCH 24/90] refactor: Allow sourcefile tests for a whole dir --- test/lib/linter/_linterHelper.ts | 92 +++++++++++------- .../rules/snapshots/BestPractices.ts.md | 53 ++-------- .../rules/snapshots/BestPractices.ts.snap | Bin 996 -> 975 bytes 3 files changed, 63 insertions(+), 82 deletions(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index be568945c..edabebeb7 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -68,44 +68,31 @@ export function createTestsForFixtures(fixturesPath: string) { if (!testFiles.length) { throw new Error(`Failed to find any fixtures in directory ${fixturesPath}`); } - for (const fileName of testFiles) { - if (!fileName.endsWith(".js") && - !fileName.endsWith(".xml") && - !fileName.endsWith(".json") && - !fileName.endsWith(".html") && - !fileName.endsWith(".yaml")) { - // Ignore non-JavaScript, non-XML, non-JSON, non-HTML and non-YAML files - continue; - } - let testName = fileName; - let defineTest = test.serial; - if (fileName.startsWith("_")) { - // Skip tests for files starting with underscore - defineTest = defineTest.skip as typeof test; - testName = fileName.slice(1); - } else if (fileName.startsWith("only_")) { - // Only run test when file starts with only_ - defineTest = defineTest.only as typeof test; - testName = fileName.slice(5); - } - // Executing linting in parallel might lead to OOM errors in the CI - // Therefore always use serial - defineTest(`General: ${path.basename(fixturesPath)}/${testName}`, async (t) => { - const filePaths = [fileName]; - const {lintFile} = t.context; + if (fixturesPath.includes("BestPractices")) { + testDefinition({ + testName: `${path.basename(fixturesPath)}/Component.js`, + fileName: "Component.js", + fixturesPath, + filePaths: testFiles, + }); + } else { + for (const fileName of testFiles) { + if (!fileName.endsWith(".js") && + !fileName.endsWith(".xml") && + !fileName.endsWith(".json") && + !fileName.endsWith(".html") && + !fileName.endsWith(".yaml")) { + // Ignore non-JavaScript, non-XML, non-JSON, non-HTML and non-YAML files + continue; + } - const res = await lintFile({ - rootDir: fixturesPath, - pathsToLint: filePaths, - reportCoverage: true, - includeMessageDetails: true, + testDefinition({ + testName: fileName, + fileName, + fixturesPath, + filePaths: [fileName], }); - assertExpectedLintResults(t, res, fixturesPath, filePaths); - res.forEach((results) => { - results.filePath = testName; - }); - t.snapshot(res); - }); + } } } catch (err) { if (err instanceof Error) { @@ -116,6 +103,39 @@ export function createTestsForFixtures(fixturesPath: string) { } } +function testDefinition( + {testName, fileName, fixturesPath, filePaths}: + {testName: string; fileName: string; fixturesPath: string; filePaths: string[]}) { + let defineTest = test.serial; + + if (fileName.startsWith("_")) { + // Skip tests for files starting with underscore + defineTest = defineTest.skip as typeof test; + testName = fileName.slice(1); + } else if (fileName.startsWith("only_")) { + // Only run test when file starts with only_ + defineTest = defineTest.only as typeof test; + testName = fileName.slice(5); + } + // Executing linting in parallel might lead to OOM errors in the CI + // Therefore always use serial + defineTest(`General: ${testName}`, async (t) => { + const {lintFile} = t.context; + + const res = await lintFile({ + rootDir: fixturesPath, + pathsToLint: filePaths, + reportCoverage: true, + includeMessageDetails: true, + }); + assertExpectedLintResults(t, res, fixturesPath, filePaths); + res.forEach((results) => { + results.filePath = testName; + }); + t.snapshot(res); + }); +} + export function preprocessLintResultsForSnapshot(res: LintResult[]) { res.sort((a, b) => { return a.filePath.localeCompare(b.filePath); diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 24ab15d98..cff65a021 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -13,18 +13,12 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Negative_1/Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_1/manifest.json - -> Snapshot 1 - - [] - ## General: Negative_2/Component.js > Snapshot 1 @@ -34,18 +28,12 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Negative_2/Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_2/manifest.json - -> Snapshot 1 - - [] - ## General: Negative_3/Component.js > Snapshot 1 @@ -55,7 +43,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Negative_3/Component.js', messages: [], warningCount: 0, }, @@ -70,7 +58,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Negative_4/Component.js', messages: [], warningCount: 0, }, @@ -85,7 +73,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 1, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Positive_1/Component.js', messages: [ { column: 9, @@ -101,12 +89,6 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_1/manifest.json - -> Snapshot 1 - - [] - ## General: Positive_2/Component.js > Snapshot 1 @@ -116,7 +98,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Positive_2/Component.js', messages: [ { column: 9, @@ -141,27 +123,6 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_2/manifest.json - -> Snapshot 1 - - [] - -## General: Positive_3/Component.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'Component.js', - messages: [], - warningCount: 0, - }, - ] - ## General: Positive_4/Component.js > Snapshot 1 @@ -171,7 +132,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Component.js', + filePath: 'Positive_4/Component.js', messages: [ { column: 9, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 9407db35a680a9660ad6a3e7b8f858167698e9b8..65960917ade242bee29d54641ca8ba02e4cd83bc 100644 GIT binary patch literal 975 zcmV;=12FtSRzVhf_NaZqwODi>A>^M%SDx@kwRU`ye zB!2aRChJ*y+VzYzGwTpU4?Xo*35f$j2o+8UaYW((e+A;i4KADzH^dFRwu`+GJ1MD} zs`hDi-p+e(zaP(c=3cZD>+q(%^SN-+#o|47RVZP2e2Kj#THMK=c()pC=uTHFp>jyFXl9Tm+p06+own-Xh>>@`Qe_>@R63 zcIj6Fej{MP1I~NErU!iG0YCV_LM|hC{$GL@GmRHQ9VZ<%l=G=fG@r_uJ{3=8V!2o< zF zJr%Z%RywiqUZ%|HVVOVvtRLi+qtg26as zk(E#zQQ1l>ZfNC%avMf)C$(ZyIbk9m3MLgB|8FsEm=$jDg)EAB%d$utwlv7O8km7f z!9bm*RJpOBc6~jU`e|KTunt!;61JaNt1M)b#A2&CdOVlN)#W&CY+32$e*NWmAW(Lr zSkV(ky1gN1Z;H{(y3FO@fAojO0~^gz9UA+n^?!VZyje!$e@eg?1bjWqY`j$PZwF>` zlIRaYN})uhh6h~sfa@O6^MDUM;CB!Bzz4qZr~6KcNz{3!-KC?A7#ZD}*op^oD-yFkWU6cNt_)_TxbUzXfgT~A x%>&_?G|?v$(iGdCb=RNU_PA~T$6bGJ+jHA~{2XC!+m8XHzW~3Zo}LgF000Y**KGg* literal 996 zcmVhT+s?;{tSC90UZ=Sb>{<7YJ6hxOhk znSJSb>mQ2<00000000B+SI=)7MHK$tu78pKaH=8>NJ!IELIj8xJC2i92&qa@6{(Oa z5(rLcvYxf4UC)@AaY7CpkdTlN;($0HAtBl$68{0*5hwluE>zqQe*^5=PVG$_M-f)* zVxM;Q?Y#H=eeZp5=5Dkb>+p{K;+}BQ#o{A&LnvW*e3iW|THMJ!@j*4%)Sa$YLb=Lq zE3M*P+t$v0a<|#!j=xWz`Y0m#QHi`)0n`9oq{0QtUo(au5DlNogyAi* zr6LU~<05%O+k!Agn@!zQE`60l=7Vy?9gp9f@Kq_2vAD%u`!MDxL}^Ctk&H?mVJ&Y7 zn{jh?pBp7rYdlhE3_E`eyK!4?#5N@G(!&Vsa3v#QljO8I!r*(C9}xIR-i|4d+Ppw! zyFhAFE|ArEfy_{WJcPjdoWPkR@RqjnL^C{h=|3g#X8`vBEE4eYNeO)Gv;-!pOou@^ z9R|t!@?Xba6CO$B2*Tgd0O8W_1l%WpJm3WnxZ(ldd%!O~(x77~=Z~OV%p_h2b=>Qy z0fx_HtoanfbX7c;vE^c^#9&`8V=E3|8m@2bXzkd$QtUIXnruh+oK!8wjbKVU7HSpA zR?mngbDG7PH<{z6C7fm49;mQww9-8rA7sLuAB4Fs9G9^jy!JrvSi!E1>|{4JZzd66 zYCG4pSA(D@*D98GE1~WL)k?MYT5vgVx+}w=vEJBitTyWPMtG$zc#~H*R(Gql>IUDa z)z_=*%N4fO>BgcXlw*mDo~(r0h{{$PaZ@WNl-o3dJE;|u$_W$kP%x?3Xl*fVm=&)7 z4_OrRmSvGPY^m>aEiiqQf<8J+DRLu5?Gikf61T1`*x2ySl5Bdh*lG@!&-dioN}MLP zqV!4k%_9QvPhz|8B%KYmWFUQ-)CrxY*pCaIVI z6#?H6aBq@=c`3?2_7&_5(O-#rQ7UGyctF(ywmsmE2YluMe|o@&KJbHoyqJ}!^s5j2 z<^zBGz(NjqF$a8}1D?wR+xg7)!V{u}Z|sPU-Vkqp-GP*O?-zSnl5|f4L zSSjRP8BBDsJS~}_$4Jlh6VWrS%>Pf4j+q5hx=SAVpWh{C{3 Date: Thu, 25 Apr 2024 15:23:24 +0300 Subject: [PATCH 25/90] test: Add BestPractices samples --- src/linter/linter.ts | 2 +- .../BestPractices/Negative_1/Component.js | 2 +- .../BestPractices/Negative_1/manifest.json | 6 +-- .../BestPractices/Negative_2/Component.js | 2 +- .../BestPractices/Negative_2/manifest.json | 6 +-- .../BestPractices/Negative_3/Component.js | 8 ++-- .../BestPractices/Negative_4/Component.js | 8 ++-- .../BestPractices/Negative_6/Component.js | 7 +++ .../Negative_6/ParentComponent.js | 9 ++++ .../BestPractices/Negative_6/manifest.json | 45 +++++++++++++++++++ .../BestPractices/Positive_1/Component.js | 2 +- .../BestPractices/Positive_1/manifest.json | 6 +-- .../BestPractices/Positive_2/Component.js | 2 +- .../BestPractices/Positive_2/manifest.json | 6 +-- .../BestPractices/Positive_3/Component.js | 8 ++-- .../BestPractices/Positive_4/Component.js | 8 ++-- test/lib/linter/_linterHelper.ts | 10 +++-- 17 files changed, 101 insertions(+), 36 deletions(-) create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_6/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json diff --git a/src/linter/linter.ts b/src/linter/linter.ts index 87692b5de..13c51523c 100644 --- a/src/linter/linter.ts +++ b/src/linter/linter.ts @@ -89,7 +89,7 @@ export async function lintFile({ }: LinterOptions): Promise { const reader = createReader({ fsBasePath: rootDir, - virBasePath: "/", + virBasePath: namespace ? `/resources/${namespace}/` : "/", }); let resolvedFilePaths; if (pathsToLint?.length) { diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js index 2be38d9a8..9c77822b8 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js @@ -1,7 +1,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: "json", diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json index b1e865dcf..63a4fffc3 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json @@ -2,7 +2,7 @@ "_version": "1.12.0", "sap.app": { - "id": "com.ui5.troublesome.app", + "id": "mycomp", "type": "application", "i18n": "i18n/i18n.properties", "title": "{{appTitle}}", @@ -14,7 +14,7 @@ "sap.ui5": { "rootView": { - "viewName": "com.ui5.troublesome.app.view.App", + "viewName": "mycomp.view.App", "type": "XML", "id": "app" }, @@ -23,7 +23,7 @@ "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", - "viewPath": "com.ui5.troublesome.app.view", + "viewPath": "mycomp.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js index fba1394f8..d34ea7e2d 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js @@ -1,7 +1,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { manifest: "json", }, diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json index 3f9e40bf1..31637c67c 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json +++ b/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json @@ -2,7 +2,7 @@ "_version": "1.12.0", "sap.app": { - "id": "com.ui5.troublesome.app", + "id": "mycomp", "type": "application", "i18n": "i18n/i18n.properties", "title": "{{appTitle}}", @@ -14,7 +14,7 @@ "sap.ui5": { "rootView": { - "viewName": "com.ui5.troublesome.app.view.App", + "viewName": "mycomp.view.App", "type": "XML", "async": true, "id": "app" @@ -24,7 +24,7 @@ "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", - "viewPath": "com.ui5.troublesome.app.view", + "viewPath": "mycomp.view", "controlId": "app", "controlAggregation": "pages", "async": true diff --git a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js index e0b7edbc3..62cf1d6a3 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js @@ -1,14 +1,14 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: { _version: "1.12.0", "sap.app": { - id: "com.ui5.troublesome.app", + id: "mycomp", type: "application", i18n: "i18n/i18n.properties", title: "{{appTitle}}", @@ -20,7 +20,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "sap.ui5": { rootView: { - viewName: "com.ui5.troublesome.app.view.App", + viewName: "mycomp.view.App", type: "XML", id: "app", }, @@ -29,7 +29,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { config: { routerClass: "sap.m.routing.Router", viewType: "XML", - viewPath: "com.ui5.troublesome.app.view", + viewPath: "mycomp.view", controlId: "app", controlAggregation: "pages", }, diff --git a/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js index cb8450969..fb85742d2 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js @@ -1,13 +1,13 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { manifest: { _version: "1.12.0", "sap.app": { - id: "com.ui5.troublesome.app", + id: "mycomp", type: "application", i18n: "i18n/i18n.properties", title: "{{appTitle}}", @@ -19,7 +19,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "sap.ui5": { rootView: { - viewName: "com.ui5.troublesome.app.view.App", + viewName: "mycomp.view.App", type: "XML", async: true, id: "app", @@ -29,7 +29,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { config: { routerClass: "sap.m.routing.Router", viewType: "XML", - viewPath: "com.ui5.troublesome.app.view", + viewPath: "mycomp.view", controlId: "app", controlAggregation: "pages", async: true, diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js new file mode 100644 index 000000000..d0b711066 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js @@ -0,0 +1,7 @@ +sap.ui.define(["com/ui5/troublesome/app/ParentComponent"], function (ParentComponent) { + "use strict"; + + return ParentComponent.extend("mycomp.Component", { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js b/test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js new file mode 100644 index 000000000..58668af47 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.ParentComponent", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js index fba1394f8..d34ea7e2d 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js @@ -1,7 +1,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { manifest: "json", }, diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json index b1e865dcf..63a4fffc3 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json +++ b/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json @@ -2,7 +2,7 @@ "_version": "1.12.0", "sap.app": { - "id": "com.ui5.troublesome.app", + "id": "mycomp", "type": "application", "i18n": "i18n/i18n.properties", "title": "{{appTitle}}", @@ -14,7 +14,7 @@ "sap.ui5": { "rootView": { - "viewName": "com.ui5.troublesome.app.view.App", + "viewName": "mycomp.view.App", "type": "XML", "id": "app" }, @@ -23,7 +23,7 @@ "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", - "viewPath": "com.ui5.troublesome.app.view", + "viewPath": "mycomp.view", "controlId": "app", "controlAggregation": "pages" }, diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js index 2be38d9a8..9c77822b8 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js @@ -1,7 +1,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: "json", diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json index 3f9e40bf1..31637c67c 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json +++ b/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json @@ -2,7 +2,7 @@ "_version": "1.12.0", "sap.app": { - "id": "com.ui5.troublesome.app", + "id": "mycomp", "type": "application", "i18n": "i18n/i18n.properties", "title": "{{appTitle}}", @@ -14,7 +14,7 @@ "sap.ui5": { "rootView": { - "viewName": "com.ui5.troublesome.app.view.App", + "viewName": "mycomp.view.App", "type": "XML", "async": true, "id": "app" @@ -24,7 +24,7 @@ "config": { "routerClass": "sap.m.routing.Router", "viewType": "XML", - "viewPath": "com.ui5.troublesome.app.view", + "viewPath": "mycomp.view", "controlId": "app", "controlAggregation": "pages", "async": true diff --git a/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js index 29f513c90..fbf972b0b 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js @@ -1,13 +1,13 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { manifest: { _version: "1.12.0", "sap.app": { - id: "com.ui5.troublesome.app", + id: "mycomp", type: "application", i18n: "i18n/i18n.properties", title: "{{appTitle}}", @@ -19,7 +19,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "sap.ui5": { rootView: { - viewName: "com.ui5.troublesome.app.view.App", + viewName: "mycomp.view.App", type: "XML", id: "app", }, @@ -28,7 +28,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { config: { routerClass: "sap.m.routing.Router", viewType: "XML", - viewPath: "com.ui5.troublesome.app.view", + viewPath: "mycomp.view", controlId: "app", controlAggregation: "pages", }, diff --git a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js index 7b2e60096..4396d0ef5 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js @@ -1,14 +1,14 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; - return UIComponent.extend("com.ui5.troublesome.app.Component", { + return UIComponent.extend("mycomp.Component", { metadata: { interfaces: ["sap.ui.core.IAsyncContentCreation"], manifest: { _version: "1.12.0", "sap.app": { - id: "com.ui5.troublesome.app", + id: "mycomp", type: "application", i18n: "i18n/i18n.properties", title: "{{appTitle}}", @@ -20,7 +20,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "sap.ui5": { rootView: { - viewName: "com.ui5.troublesome.app.view.App", + viewName: "mycomp.view.App", type: "XML", async: true, id: "app", @@ -30,7 +30,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { config: { routerClass: "sap.m.routing.Router", viewType: "XML", - viewPath: "com.ui5.troublesome.app.view", + viewPath: "mycomp.view", controlId: "app", controlAggregation: "pages", async: true, diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index edabebeb7..924270d17 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -71,9 +71,12 @@ export function createTestsForFixtures(fixturesPath: string) { if (fixturesPath.includes("BestPractices")) { testDefinition({ testName: `${path.basename(fixturesPath)}/Component.js`, + namespace: "mycomp", fileName: "Component.js", fixturesPath, - filePaths: testFiles, + // Needed, because without a namespace, TS's type definition detection + // does not function properly for the inheritance case + filePaths: testFiles.map((fileName) => `resources/mycomp/${fileName}`), }); } else { for (const fileName of testFiles) { @@ -104,8 +107,8 @@ export function createTestsForFixtures(fixturesPath: string) { } function testDefinition( - {testName, fileName, fixturesPath, filePaths}: - {testName: string; fileName: string; fixturesPath: string; filePaths: string[]}) { + {testName, fileName, fixturesPath, filePaths, namespace}: + {testName: string; fileName: string; fixturesPath: string; filePaths: string[], namespace?: string}) { let defineTest = test.serial; if (fileName.startsWith("_")) { @@ -124,6 +127,7 @@ function testDefinition( const res = await lintFile({ rootDir: fixturesPath, + namespace, pathsToLint: filePaths, reportCoverage: true, includeMessageDetails: true, From 8bb2b38ae53a4d9374c11eb42f9e2e7ab3e4cba9 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 15:28:19 +0300 Subject: [PATCH 26/90] fix: Allow filtering for BestPractices tests --- test/lib/linter/_linterHelper.ts | 3 ++- test/lib/linter/rules/BestPractices.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 924270d17..83e1b64df 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -69,10 +69,11 @@ export function createTestsForFixtures(fixturesPath: string) { throw new Error(`Failed to find any fixtures in directory ${fixturesPath}`); } if (fixturesPath.includes("BestPractices")) { + const dirName = fixturesPath.split("/").pop(); testDefinition({ testName: `${path.basename(fixturesPath)}/Component.js`, namespace: "mycomp", - fileName: "Component.js", + fileName: `${dirName}/Component.js`, fixturesPath, // Needed, because without a namespace, TS's type definition detection // does not function properly for the inheritance case diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/BestPractices.ts index c073945d9..11b62da18 100644 --- a/test/lib/linter/rules/BestPractices.ts +++ b/test/lib/linter/rules/BestPractices.ts @@ -12,7 +12,7 @@ const testSubDirs = readdirSync(fixturesPath); for (const subDir of testSubDirs) { const dirPath = path.join(fixturesPath, subDir); - if (!subDir.startsWith("_") && lstatSync(dirPath).isDirectory()) { + if (lstatSync(dirPath).isDirectory()) { runLintRulesTests(fileName, dirPath); } } From c78eacaf0f13203c970a94362cdaa18e7424a897 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 15:36:41 +0300 Subject: [PATCH 27/90] fix: Analyze only Component.js files --- src/linter/ui5Types/BestPractices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index adcfbae29..ea322c7a8 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -37,7 +37,7 @@ export default function analyzeComponentJson( parent = parent.parent; } - if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("Component.js") || !classDesc) { + if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("/Component.js") || !classDesc) { return; } From b95900cbb354b3fe57422b7552c52c8dca0a8428 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 15:40:35 +0300 Subject: [PATCH 28/90] test: Add negative test case --- .../BestPractices/Negative_5/Component.js | 6 +++ .../Negative_5/ParentComponent.js | 9 ++++ .../BestPractices/Negative_5/manifest.json | 47 +++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_5/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_5/Component.js new file mode 100644 index 000000000..80ece1eae --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_5/Component.js @@ -0,0 +1,6 @@ +sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { + "use strict"; + + return ParentComponent.extend("mycomp.Component", { + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js b/test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js new file mode 100644 index 000000000..58668af47 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.ParentComponent", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json new file mode 100644 index 000000000..31637c67c --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json @@ -0,0 +1,47 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages", + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} From ddf092d52248ca2ca1a3526fed7b69e7861a21f0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 15:49:12 +0300 Subject: [PATCH 29/90] fix: Test Component's namespace --- .../fixtures/linter/rules/BestPractices/Negative_6/Component.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js index d0b711066..df73c9961 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js @@ -1,4 +1,4 @@ -sap.ui.define(["com/ui5/troublesome/app/ParentComponent"], function (ParentComponent) { +sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { "use strict"; return ParentComponent.extend("mycomp.Component", { From e94be3f897b69678f8a893a361fe5c51a90568ac Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:00:38 +0300 Subject: [PATCH 30/90] fix: Tests --- .../BestPractices/Negative_6/Component.js | 4 +- .../rules/snapshots/BestPractices.ts.md | 71 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 975 -> 1127 bytes 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js index df73c9961..34460fe40 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js @@ -2,6 +2,8 @@ sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { "use strict"; return ParentComponent.extend("mycomp.Component", { - interfaces: ["sap.ui.core.IAsyncContentCreation"], + metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + }, }); }); diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index cff65a021..8532d55be 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -64,6 +64,52 @@ Generated by [AVA](https://avajs.dev). }, ] +## General: Negative_5/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_5/Component.js', + messages: [], + warningCount: 0, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_5/Component.js', + messages: [], + warningCount: 0, + }, + ] + +## General: Negative_6/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_6/Component.js', + messages: [], + warningCount: 0, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_6/Component.js', + messages: [], + warningCount: 0, + }, + ] + ## General: Positive_1/Component.js > Snapshot 1 @@ -123,6 +169,31 @@ Generated by [AVA](https://avajs.dev). }, ] +## General: Positive_3/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Positive_3/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View and Routing are not configured to load targets asynchronously', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + ## General: Positive_4/Component.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 65960917ade242bee29d54641ca8ba02e4cd83bc..1fae415a10b4dfcdeb9dfe5f3987b35f0bba9b0b 100644 GIT binary patch literal 1127 zcmV-t1ep6lRzVo)?;VOdd8X=Cj)P^Mm@%u}m3glEawzMPtx0-XY7K&OeGCE#9iLFqFz z;i+|@c|$DAx&lq&EIIwy38A&pi>fVc_$YdumU1XXunSz_>g?Sy3go;?!25&|)vyir$J7Hm_cH;%^n~PmPfR{>fbU#jA{8qt z*~r2(o(kGc*@N?*NHiV78Qx`2MPjMIm!dZ=6^UhgF!k@Rt|(>MGrrhhT-Ml%YFl46 z7}tVHWtpdB-EXwDs4=Tppm>d0t{cJ{#?7Ym*0hqUZGz3nG^cyhED6i~!1NwFpr?&s zR|ZD1Cls%BW<0-UZOdFL6xx0zZ+I*3sb-;=FP1JA9x7PX^1VWJzPehStCq`E@8PoG zHC|kpTP>D~3w)teo-fW{$g|~UD-cZ~E$gIc`*}}kkzWpHTvXBuX&1HN)>o4G(h6PY zo?yOYgSEw!W=7cV4p}|m4a4e6v*~WmNU*HysqcYuRR_520M{L0-2vWqfL|Tp zRTuco9j!Y#%H4K>?_J;z7q~A46jQ)EDd530a6KIvo*5I_dSpd3)w&4#>+d#=c4@y6 z>smF3T5(TmMIv59MyeKX`GwdN7w(oK&=JzJv?qFoMfCqk(g@j(I}=R&;gD|ca44Ag t!^9sZ{xH@b#vNEE{%}xdb~vz3{9)n`kDv8O{NXVm=}&X(-mBFi007Y7A2k2~ literal 975 zcmV;=12FtSRzVhf_NaZqwODi>A>^M%SDx@kwRU`ye zB!2aRChJ*y+VzYzGwTpU4?Xo*35f$j2o+8UaYW((e+A;i4KADzH^dFRwu`+GJ1MD} zs`hDi-p+e(zaP(c=3cZD>+q(%^SN-+#o|47RVZP2e2Kj#THMK=c()pC=uTHFp>jyFXl9Tm+p06+own-Xh>>@`Qe_>@R63 zcIj6Fej{MP1I~NErU!iG0YCV_LM|hC{$GL@GmRHQ9VZ<%l=G=fG@r_uJ{3=8V!2o< zF zJr%Z%RywiqUZ%|HVVOVvtRLi+qtg26as zk(E#zQQ1l>ZfNC%avMf)C$(ZyIbk9m3MLgB|8FsEm=$jDg)EAB%d$utwlv7O8km7f z!9bm*RJpOBc6~jU`e|KTunt!;61JaNt1M)b#A2&CdOVlN)#W&CY+32$e*NWmAW(Lr zSkV(ky1gN1Z;H{(y3FO@fAojO0~^gz9UA+n^?!VZyje!$e@eg?1bjWqY`j$PZwF>` zlIRaYN})uhh6h~sfa@O6^MDUM;CB!Bzz4qZr~6KcNz{3!-KC?A7#ZD}*op^oD-yFkWU6cNt_)_TxbUzXfgT~A x%>&_?G|?v$(iGdCb=RNU_PA~T$6bGJ+jHA~{2XC!+m8XHzW~3Zo}LgF000Y**KGg* From 455267ac180024869c29ef9158a7ab2648cf916b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:01:18 +0300 Subject: [PATCH 31/90] fix: Eslint --- test/lib/linter/_linterHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 83e1b64df..29c68394e 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -109,7 +109,7 @@ export function createTestsForFixtures(fixturesPath: string) { function testDefinition( {testName, fileName, fixturesPath, filePaths, namespace}: - {testName: string; fileName: string; fixturesPath: string; filePaths: string[], namespace?: string}) { + {testName: string; fileName: string; fixturesPath: string; filePaths: string[]; namespace?: string}) { let defineTest = test.serial; if (fileName.startsWith("_")) { From 61992134e624698598d3fdbb9b4e35f4a7b4eec2 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:05:03 +0300 Subject: [PATCH 32/90] test: Add positive case --- .../BestPractices/Positive_5/Component.js | 9 ++++ .../Positive_5/ParentComponent.js | 9 ++++ .../BestPractices/Positive_5/manifest.json | 47 +++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_5/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_5/Component.js new file mode 100644 index 000000000..34460fe40 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_5/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { + "use strict"; + + return ParentComponent.extend("mycomp.Component", { + metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js b/test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js new file mode 100644 index 000000000..58668af47 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.ParentComponent", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json new file mode 100644 index 000000000..0e4163721 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json @@ -0,0 +1,47 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app", + "async": true + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages", + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} From aa6de7c004b277245c0565fc25bea4cc00074ad8 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:05:56 +0300 Subject: [PATCH 33/90] fix: Update snapshots --- .../rules/snapshots/BestPractices.ts.md | 42 + .../rules/snapshots/BestPractices.ts.snap | Bin 1127 -> 1285 bytes .../rules/snapshots/CSPCompliance.ts.md | 76 + .../rules/snapshots/CSPCompliance.ts.snap | Bin 825 -> 876 bytes .../rules/snapshots/NoDeprecatedApi.ts.md | 1243 +++++++++++++++++ .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 6753 -> 12789 bytes .../linter/rules/snapshots/NoGlobals.ts.md | 175 +++ .../linter/rules/snapshots/NoGlobals.ts.snap | Bin 1599 -> 1699 bytes .../rules/snapshots/NoPseudoModules.ts.md | 49 + .../rules/snapshots/NoPseudoModules.ts.snap | Bin 658 -> 692 bytes test/lib/linter/snapshots/linter.ts.md | 269 +++- test/lib/linter/snapshots/linter.ts.snap | Bin 8061 -> 9660 bytes 12 files changed, 1848 insertions(+), 6 deletions(-) diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 8532d55be..0a5aa9137 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -227,3 +227,45 @@ Generated by [AVA](https://avajs.dev). warningCount: 2, }, ] + +## General: Positive_5/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_5/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + { + column: 9, + fatal: undefined, + line: 4, + message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 2, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_5/Component.js', + messages: [], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 1fae415a10b4dfcdeb9dfe5f3987b35f0bba9b0b..067087b3eaceafc41f1366d98c2e92f1db9f2aac 100644 GIT binary patch literal 1285 zcmV+g1^W6yRzVdX(q zCz_0;bW^Gn;>$I@w9xE!H@llys#uazf}$nh zM=MxvcJFSc&fdGs+)a$APz7In5EMa?R#G2S#799PKKM}k2S`Cse6aZOBnm?DNwZ&Z zcbeTv)`VBve|vVNIB%=`v+irxgtoLTo?~Z)6b`pfvPVUUYim(l zOeLpPxuT?yI&sOhT*)i$g3|8gl|q4Qex6=85k>7oF*1$=NCP-bkwX+d?KpgysC5;O z$3go+1Uf);sx>IO1mHyg?*do_@B@HR0y5Ne6nSj^lE`Z^)-Oj!MnJ=$2iVM)JTJtHTyy)3&s(vgWs7rMFSH&U z=@PB_;@q~y#md5Uc}ch)k3&n`k(MlVP8#b7quCM0PFtwW)&t9QfaMmjOb;}c69JZ6 zz;a@svCITmZUM{8Kx3Kp!P5A>4NLO`fE<8_{O~mDcs|@1c!22D+Bemq{Sv?p06zkV z5OAD;0s$}iKpUgz3IQJwaGijk2pBSe83TC6@C*%i$%@Oypkzh%&aAj%^qUpy`}=&5 z_jj}J{q>jiUR$JxExNgC$pzK2E7_F$k5|hE``f$Ka!$F{rhbcsj&G|@_yWMKwd;Eb z$Zl3AJk_sGs4Zn%lAuet>Z{W`BNWJZhk*A8J+fgv*dI|d*s)&-__awSN1J5wu>pK- z0z)BRQi*yN9?2`aT9(al?(EhjqQf3r$hM?tjthBg(Po%h_h;vn((DOKEHN$% zY))0RB};v|_g61*W-E653_lU6%O;M@dz6?Pbq22bWYTl1`>7i6bui`hc!cC>0`$L;#U#-$ps%|C880^}_eS1bz0(#uVpjUGhf z*C+@-zxzK(`X-v~I&8W`>)-H9O}O+X8uJPP?-THeAK5fC&}Y=rK)0!-fnqrWIAs7A z3}Dd!-Y|gQ4B!P5_|)vpJ28sgG=XnT;7=2{I|QUcz*`~U-Y{?>>=_;z5ZZchPL$Q6 zsMps&W$LZcRv{K0RqiOoO|caTe-7!%TD)QjQA*-Gd0=K8_-wh3G{fmIXu#svN_fw>UyeF!+>J=yL& v7$?KP17YClFtD`t`kQOtx5L0I5nweE9E^LGbAy9%4}kPHg-*02?kE5NXr*ts literal 1127 zcmV-t1ep6lRzVo)?;VOdd8X=Cj)P^Mm@%u}m3glEawzMPtx0-XY7K&OeGCE#9iLFqFz z;i+|@c|$DAx&lq&EIIwy38A&pi>fVc_$YdumU1XXunSz_>g?Sy3go;?!25&|)vyir$J7Hm_cH;%^n~PmPfR{>fbU#jA{8qt z*~r2(o(kGc*@N?*NHiV78Qx`2MPjMIm!dZ=6^UhgF!k@Rt|(>MGrrhhT-Ml%YFl46 z7}tVHWtpdB-EXwDs4=Tppm>d0t{cJ{#?7Ym*0hqUZGz3nG^cyhED6i~!1NwFpr?&s zR|ZD1Cls%BW<0-UZOdFL6xx0zZ+I*3sb-;=FP1JA9x7PX^1VWJzPehStCq`E@8PoG zHC|kpTP>D~3w)teo-fW{$g|~UD-cZ~E$gIc`*}}kkzWpHTvXBuX&1HN)>o4G(h6PY zo?yOYgSEw!W=7cV4p}|m4a4e6v*~WmNU*HysqcYuRR_520M{L0-2vWqfL|Tp zRTuco9j!Y#%H4K>?_J;z7q~A46jQ)EDd530a6KIvo*5I_dSpd3)w&4#>+d#=c4@y6 z>smF3T5(TmMIv59MyeKX`GwdN7w(oK&=JzJv?qFoMfCqk(g@j(I}=R&;gD|ca44Ag t!^9sZ{xH@b#vNEE{%}xdb~vz3{9)n`kDv8O{NXVm=}&X(-mBFi007Y7A2k2~ diff --git a/test/lib/linter/rules/snapshots/CSPCompliance.ts.md b/test/lib/linter/rules/snapshots/CSPCompliance.ts.md index 3e98b71f8..dbc40c6ee 100644 --- a/test/lib/linter/rules/snapshots/CSPCompliance.ts.md +++ b/test/lib/linter/rules/snapshots/CSPCompliance.ts.md @@ -4,6 +4,82 @@ The actual snapshot is saved in `CSPCompliance.ts.snap`. Generated by [AVA](https://avajs.dev). +## General: NoInlineJS.html + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'NoInlineJS.html', + messages: [ + { + column: 2, + fatal: undefined, + line: 9, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + { + column: 2, + fatal: undefined, + line: 17, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + { + column: 2, + fatal: undefined, + line: 25, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + { + column: 2, + fatal: undefined, + line: 31, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + { + column: 2, + fatal: undefined, + line: 47, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + { + column: 2, + fatal: undefined, + line: 55, + message: 'Use of unsafe inline script', + messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', + ruleId: 'ui5-linter-csp-unsafe-inline-script', + severity: 1, + }, + ], + warningCount: 6, + }, + ] + +## General: NoInlineJS_negative.html + +> Snapshot 1 + + [] + ## General: CSPCompliance/NoInlineJS.html > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap b/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap index 072f8874b733dc85070687444a94d1d95cd29e49..d5ca286a37f4ffa9c5cbc3eec0550d66855256c8 100644 GIT binary patch literal 876 zcmV-y1C#tgRzVJoSo zgSX%#Dj$mo00000000B+m(6bsVI0T5znz`8-Lh>tcsW>_cnQ0srK%zlDUmwRq#-0i zo}GQBeVCnDGtZVvB#4tgz(pb1=T!6`eVKpO^3R z@_Bxl6Mz8#OGxV>b$1Z3X`)1xN+nPMM4%$k&cvjj0dO9`H2@C*yav!q zz$R)hq#dlCTjO_021}y?Zlv(@?(r*!Pmw@{OJR;x;0nZ3{MYF-@)8Mrj{9B5_7l}6Jki5ppNakXBCz47m z-$XJW%XJDsYP7%MD1fT~R}|p30z6iL&kArM4?NDN-b|hSW(FCr^T3-tpsBzb71*T$ z(<<;O(pt){b=Z$anExAaA+v3yjnZJ(JM)7#aWv{xPqdD(Z$EiYsaFN?U; z%b^{Jrc7BEx2=1)WWo)T?qegqC%Grf*d{@}h<@J+NHp3m3)e?i%kTt8e z->~|t{R5k=K1=#dVOtLGXWQyEHoSE+-#Rqx)Q0RWHG61qi!(e>8`y4dNHYmqE+4HY z&AyfxthmCHJgC@Vv-0f{m2a1*%y|hT{n&%=Z(FU zv7a~gLmB&Dvri((>Nz6F36D=ODW>?`S>#CH_bBqy1d^=3c4qyN@v#xV(R2m#Y;I+N zCks4T;K>5dg8m6-f#<(up9P*Q@GM03S>VY6&p*pP2_)8U1IeF=KVJc*q0;N?82|uj CeVkVS literal 825 zcmV-91IGM8RzVZR#ayd{2M4&9up_WO% z4B#4oI{=;m_yAy#fW6c_NIO+t;I^dHZ`t495843IKpTll1Z*M&qz+J@?Jx3xRr!qP z_@EqyDAkH(co6u(wBPV#yp%>_L(XB6xyRPoWjMm+B_`*8+Y*%GN4cvWWz={WvMLV~ zC-q%sfhWA`s>`C3j5dBs8$W~e`vg29;0XcG33y4sYXaU=JNR@GycUE1L^1d*(Vi4q zzp)U>R4gAxQiGsqKGekntf6 zd`ttH3T#(_!z!?(0^cL8CG1*<{k#TLG~lKN+|_`m8t_#EuIRv1Jz>{7>~D48oeuoe zfh`8G-vBNdz?Vpy3A@o@KVt%OCUDgRZkxbk6ZmWb^$hShldzi|_E#C;O$PXu0S2=` zF$;(+@F~)L345la-1S8LXtwV*YF@K)Qi-S Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'ModuleImport.js', + messages: [ + { + column: 16, + fatal: undefined, + line: 1, + message: 'Import of deprecated module \'sap/ui/model/odata/ODataModel\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: NoDeprecatedApi.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 17, + fatalErrorCount: 0, + filePath: 'NoDeprecatedApi.js', + messages: [ + { + column: 18, + fatal: undefined, + line: 2, + message: 'Import of deprecated module \'sap/m/DateTimeInput\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 41, + fatal: undefined, + line: 2, + message: 'Import of deprecated module \'sap/base/util/includes\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 107, + fatal: undefined, + line: 2, + message: 'Import of deprecated module \'sap/ui/generic/app/navigation/service/NavigationHandler\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 9, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 10, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 13, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'plugins\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 21, + message: 'Use of deprecated property \'groupBy\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 24, + message: 'Call to deprecated function \'includes\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 26, + message: 'Call to deprecated function \'getCompatibilityVersion\' of class \'Configuration\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 27, + message: 'Call to deprecated function \'getCompatibilityVersion\' of class \'Configuration\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 29, + message: 'Access of deprecated property \'webview\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 30, + message: 'Access of deprecated property \'webview\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 32, + message: 'Access of deprecated property \'AnimationMode\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 34, + message: 'Access of deprecated property \'MessageType\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 36, + message: 'Access of deprecated property \'Date\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 39, + message: 'Call to deprecated function \'storeInnerAppState\' of class \'NavigationHandler\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: NoDeprecatedApi_negative.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'NoDeprecatedApi_negative.js', + messages: [], + warningCount: 0, + }, + ] + +## General: PartialDeprecation.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'PartialDeprecation.js', + messages: [], + warningCount: 0, + }, + ] + +## General: PrototypeClass.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'PrototypeClass.js', + messages: [ + { + column: 3, + fatal: undefined, + line: 10, + message: 'Call to deprecated function \'setVisibleRowCount\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLFragment.fragment.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 6, + fatalErrorCount: 0, + filePath: 'XMLFragment.fragment.xml', + messages: [ + { + column: 2, + fatal: undefined, + line: 6, + message: 'Import of deprecated module \'sap/m/DateTimeInput\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 10, + fatal: undefined, + line: 8, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 15, + fatal: undefined, + line: 10, + message: 'Use of deprecated property \'groupBy\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 11, + message: 'Use of deprecated property \'plugins\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 11, + fatal: undefined, + line: 17, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 17, + message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLFragmentDefinition.fragment.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 6, + fatalErrorCount: 0, + filePath: 'XMLFragmentDefinition.fragment.xml', + messages: [ + { + column: 2, + fatal: undefined, + line: 7, + message: 'Import of deprecated module \'sap/m/DateTimeInput\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 10, + fatal: undefined, + line: 9, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 15, + fatal: undefined, + line: 11, + message: 'Use of deprecated property \'groupBy\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 12, + message: 'Use of deprecated property \'plugins\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 11, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLHtmlSvg.view.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 4, + fatalErrorCount: 0, + filePath: 'XMLHtmlSvg.view.xml', + messages: [ + { + column: 1, + line: 6, + message: 'Usage of native HTML in XML Views/Fragments is deprecated', + messageDetails: '{@link topic:be54950cae1041f59d4aa97a6bade2d8 Using Native HTML in XML Views (deprecated)}', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 1, + line: 8, + message: 'Usage of SVG in XML Views/Fragments is deprecated', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 2, + line: 9, + message: 'Usage of SVG in XML Views/Fragments is deprecated', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + line: 10, + message: 'Usage of SVG in XML Views/Fragments is deprecated', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLRequire.view.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'XMLRequire.view.xml', + messages: [ + { + column: 2, + fatal: undefined, + line: 4, + message: 'Import of deprecated module \'sap/ui/core/Message\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLTemplatingRequire.view.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 2, + fatalErrorCount: 0, + filePath: 'XMLTemplatingRequire.view.xml', + messages: [ + { + column: 2, + fatal: undefined, + line: 6, + message: 'Import of deprecated module \'sap/ui/core/Message\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 8, + fatal: undefined, + line: 9, + message: 'Import of deprecated module \'sap/ui/model/odata/ODataModel\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: XMLView.view.xml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 6, + fatalErrorCount: 0, + filePath: 'XMLView.view.xml', + messages: [ + { + column: 2, + fatal: undefined, + line: 7, + message: 'Import of deprecated module \'sap/m/DateTimeInput\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 10, + fatal: undefined, + line: 9, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 15, + fatal: undefined, + line: 11, + message: 'Use of deprecated property \'groupBy\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 12, + message: 'Use of deprecated property \'plugins\' of class \'Table\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 11, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: jQuery-device.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 3, + fatalErrorCount: 0, + filePath: 'jQuery-device.js', + messages: [ + { + column: 15, + fatal: undefined, + line: 2, + message: 'Access of deprecated property \'device\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 11, + fatal: undefined, + line: 3, + message: 'Access of deprecated property \'os\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + { + column: 18, + fatal: undefined, + line: 4, + message: 'Access of deprecated property \'os\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-property', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: jQuery-plugins.js + +> Snapshot 1 + + [ + { + coverageInfo: [ + { + category: 1, + column: 18, + line: 3, + message: 'Unable to analyze this method call because the type of identifier "outerHTML" in "jQuery("#button").outerHTML()"" could not be determined', + }, + { + category: 1, + column: 2, + line: 4, + message: 'Unable to analyze this method call because the type of identifier "root" in "jQuery("#content").root({})"" could not be determined', + }, + { + category: 1, + column: 15, + line: 5, + message: 'Unable to analyze this method call because the type of identifier "uiarea" in "jQuery("#content").uiarea(0)"" could not be determined', + }, + ], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'jQuery-plugins.js', + messages: [ + { + column: 16, + fatal: undefined, + line: 2, + message: 'Call to deprecated function \'control\' of class \'JQueryStatic\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: jQuery.sap.js + +> Snapshot 1 + + [ + { + coverageInfo: [ + { + category: 1, + 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: 9, + fatalErrorCount: 0, + filePath: 'jQuery.sap.js', + messages: [ + { + 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, + }, + { + 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: '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, + }, + ], + warningCount: 0, + }, + ] + +## General: library.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 11, + fatalErrorCount: 0, + filePath: 'library.js', + messages: [ + { + column: 2, + fatal: undefined, + line: 9, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 10, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 11, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 12, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 16, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 19, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 22, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 25, + message: 'Call to Library.init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 30, + message: 'Call to LibInit() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 35, + message: 'Call to init() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 40, + message: 'Call to intRenames() must be declared with property {apiVersion: 2}', + messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', + ruleId: 'ui5-linter-no-partially-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: library_negative.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'library_negative.js', + messages: [], + warningCount: 0, + }, + ] + +## General: manifest.json + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 23, + fatalErrorCount: 0, + filePath: 'manifest.json', + messages: [ + { + column: 17, + fatal: undefined, + line: 47, + message: 'Use of deprecated library \'sap.ca.scfld.md\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 48, + message: 'Use of deprecated library \'sap.ca.ui\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 49, + message: 'Use of deprecated library \'sap.fe.common\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 50, + message: 'Use of deprecated library \'sap.fe.plugins\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 51, + message: 'Use of deprecated library \'sap.fe.semantics\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 52, + message: 'Use of deprecated library \'sap.landvisz\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 53, + message: 'Use of deprecated library \'sap.makit\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 54, + message: 'Use of deprecated library \'sap.me\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 55, + message: 'Use of deprecated library \'sap.sac.grid\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 56, + message: 'Use of deprecated library \'sap.ui.commons\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 57, + message: 'Use of deprecated library \'sap.ui.suite\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 58, + message: 'Use of deprecated library \'sap.ui.ux3\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 59, + message: 'Use of deprecated library \'sap.ui.vtm\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 60, + message: 'Use of deprecated library \'sap.uiext.inbox\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 61, + message: 'Use of deprecated library \'sap.webanalytics.core\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 62, + message: 'Use of deprecated library \'sap.zen.commons\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 63, + message: 'Use of deprecated library \'sap.zen.crosstab\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 64, + message: 'Use of deprecated library \'sap.zen.dsh\'', + ruleId: 'ui5-linter-no-deprecated-library', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 67, + message: 'Use of deprecated component \'sap.zen.dsh.fioriwrapper\'', + ruleId: 'ui5-linter-no-deprecated-component', + severity: 2, + }, + { + column: 13, + fatal: undefined, + line: 79, + message: 'Use of deprecated property \'sap.ui5/resources/js\'', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 21, + fatal: undefined, + line: 92, + message: 'Use of deprecated property \'sap.ui5/models/odata-v4/settings/synchronizationMode\' of sap.ui.model.odata.v4.ODataModel', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 21, + fatal: undefined, + line: 98, + message: 'Use of deprecated property \'sap.ui5/models/odata-v4-via-dataSource/settings/synchronizationMode\' of sap.ui.model.odata.v4.ODataModel', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 17, + fatal: undefined, + line: 102, + message: 'Use of deprecated model type \'sap.ui5/models/odata/type="sap.ui.model.odata.ODataModel"\'', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: manifest_negative.json + +> Snapshot 1 + + [] + +## General: manifest_negative_empty.json + +> Snapshot 1 + + [] + +## General: sap.ui.jsview.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'sap.ui.jsview.js', + messages: [ + { + column: 1, + fatal: undefined, + line: 1, + message: 'Call to deprecated function \'jsview\' (sap.ui.jsview)', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: sap.ui.require-nested.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'sap.ui.require-nested.js', + messages: [ + { + column: 6, + fatal: undefined, + line: 6, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: sap.ui.require-toplevel.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'sap.ui.require-toplevel.js', + messages: [ + { + column: 3, + fatal: undefined, + line: 3, + message: 'Use of deprecated property \'tap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: ui5.yaml + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'ui5.yaml', + messages: [ + { + column: 7, + fatal: undefined, + line: 11, + message: 'Use of deprecated library \'sap.landvisz\'', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + ## General: NoDeprecatedApi/ModuleImport.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.snap index e199c7d811fce71b81f3d24a164a4f29f68a3235..4eb8d2802f1aec0455636090d5bca53e6d485954 100644 GIT binary patch literal 12789 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 DpkTLd diff --git a/test/lib/linter/rules/snapshots/NoGlobals.ts.md b/test/lib/linter/rules/snapshots/NoGlobals.ts.md index e9db4e6d5..81182c883 100644 --- a/test/lib/linter/rules/snapshots/NoGlobals.ts.md +++ b/test/lib/linter/rules/snapshots/NoGlobals.ts.md @@ -4,6 +4,181 @@ The actual snapshot is saved in `NoGlobals.ts.snap`. Generated by [AVA](https://avajs.dev). +## General: NoGlobals.js + +> Snapshot 1 + + [ + { + coverageInfo: [ + { + category: 1, + column: 4, + line: 9, + message: 'Unable to analyze this method call because the type of identifier "helperFunction" in "cust.lib.helperFunction()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 14, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "sap.ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 15, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "window["sap"].ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 16, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "window.sap.ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 17, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "globalThis.sap.ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 18, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "self.sap.ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 20, + message: 'Unable to analyze this method call because the type of identifier "requireSync" in "that.sap.ui.requireSync()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 29, + message: 'Unable to analyze this method call because the type of identifier "require" in "jQuery.sap.require()"" could not be determined', + }, + { + category: 1, + column: 4, + line: 32, + message: 'Unable to analyze this method call because the type of identifier "stub" in "sinon.stub()"" could not be determined', + }, + ], + errorCount: 11, + fatalErrorCount: 0, + filePath: 'NoGlobals.js', + messages: [ + { + column: 8, + fatal: undefined, + line: 8, + message: 'Access of global variable \'sap\' (sap.m.Button)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 19, + fatal: undefined, + line: 11, + message: 'Access of global variable \'sap\' (sap.m)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 14, + message: 'Access of global variable \'sap\' (sap.ui.requireSync)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 15, + message: 'Access of global variable \'sap\' (window)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 16, + message: 'Access of global variable \'sap\' (window.sap.ui.requireSync)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 18, + message: 'Access of global variable \'sap\' (self.sap.ui.requireSync)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 20, + message: 'Access of global variable \'sap\' (that.sap.ui.requireSync)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 25, + message: 'Access of global variable \'sap\' (window)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 27, + message: 'Access of global variable \'jQuery\' (jQuery.ajax)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 28, + message: 'Access of global variable \'jQuery\' (jQuery)', + ruleId: 'ui5-linter-no-globals-js', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 29, + message: 'Use of deprecated API \'jQuery.sap.require\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: NoGlobals_Negative.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'NoGlobals_Negative.js', + messages: [], + warningCount: 0, + }, + ] + ## General: NoGlobals/NoGlobals.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoGlobals.ts.snap b/test/lib/linter/rules/snapshots/NoGlobals.ts.snap index 9fc83eb78640b3fcb812f54dd1835b9b007983ef..5e4af53f9f7bb5b31b32880f5aeeb96bf5c8e384 100644 GIT binary patch literal 1699 zcmV;U23+|;RzV1@yY00000000B+ncHt1R~^ScXY9Rr*WQcw;$6Fek&&>Q)C&zDafy)97Sc#G zP12+nK?Ae9$KEmH8FyyZj;prfQk7d;=tZcAzBKfqLV{GNQmYCO59O%{@fUyu;u#4E z6#)-q$GcnmOz@Z}R%~_l={IxE_x$GfIkPjr-S5kbP0MM0)qC=?^iAKA-4oK5u3>#z zKjoaToTg!Ujb+dDY-82yIKKDwm)mW_Hy)a~GD3>pN2G;z8*mgTiDXeEj=Qe0A;cic z=ktgRLLjn292%il{kAYtSe*p>t4vYRm$$Oj2vgHeH7#0cz!~`OV$O&gC_QFgLS>jL%K9qtx zQ(&av@sx4{j&8pJ(;_jShDI7rrNK(Wx6_Iw5t1AkgWJd8%osRh@Vzlbk_<^cnSsw{ z;6er-%fO2nMUo0h?#RO3S?FZpsVrR1Dw1?aa(W!@ABVMZcwrn~8&@P_A<2UiaA5+T zn1Gii;LQm|k_kz^l7qz@Je7l2a`2m+BFTm%7xK`~!;^WqoQGfM70I|NNu4Rc0|n?7 z;MoHFtN{Nmz|o>2&4r|Ai|}9(){5|45q@5Te-z=iNky6uNxv`&XD4BG5-v@`tCR4b zN%&YvkrqPI`%3Uo3D&PpeZB-&uEy_{pix$&#gOz=8P1i#EyFWq_-Ppu6*yK=q>~}( zmnzV#z}G79QU%_uK(PvUR~2a~B<)neuEM1%yjq2~t8i!v&P^%Oa!Be=!J|{~;uO3- z1%J32*J^NYO_5eYQl|#ptJ9vZ!Ic`kQ-hg0oUJR;YDntV;bI+rSchNK;rDf@Ps8bH zMLMNQ)2q|4HVrRK!)w#ieT*_;Sf{H~McOp^PV6j@4bU z`=hFQ)G}?^9~)D~QvFv=|5*Dj=WU~DN!@pJ!#1pqN2Ts}Oiy2te#dF+EyJ?(rfeBq zuQwode`8hZ&Z2I%rR|%GrgZh$jTT&ucg3`2dyi4%B2aweMxb!zBVE&#_ifm%O%9&1+US~%E$43{f_wym zOM8M~-L%`z`WJgBW*^=^FbWYczO#og8vE+DC`OQYdQV6!1r71Jj_K_$8j}$;zO^^c z3280vFAn9K!olwt{{G@{XlD-Mi5rJu6T$MCu5>p72>tUnv3fnCdhZ5Q@A=(k|65?% zj@{@TN0yx2v81#znh1Wk2S=%i9m-X8YPpT$t(Nq>UIm-aFMZ8$&49q1XROZY^Sy0b zY24BEeaF64y+*fd$&>BDVXbR^V!<+PU%Csnv#`0Kx3H}K50LicnsiNnu$$U00FfOBC$|L$i@$p?%zWuRv05L@Lh+;kx!)A+f085YP2*qc1S^72J zUk8vzL?0wR75#mTs>&H)@98|uwrJqw)%Jo;eOZtXs zd4tnacfGfgFFjxHPum&YE!)w(cQp&fsu_i^@9$mwK-l2>@+rAw_~x3trqd^$zM)Rv zFM&S;H33I=>-3$!UZ+pB@UGM7t6Y;+aA}WRzvH))k+*GZbj#RaA3qr0$B)F8ZEV@b zmThd=#+Get*~XS_Y}v+^ZEV@bmThd=#+Get*~XS_Y}v+^?VkK88C$lyyPIRn_W!~V tTeh)f8(X%qWgAQ@u^gbBX1oXx(?Ib@ zdMFK(sUM3700000000B!ncHt1)g8w_XY9RrcfI#r@7hEi8L2i2-j=kLdWk9pXhWnD zl8|swA?@t$v3K0@%rY};#|ThMD|!o1E~=>Dg_H+WsSTJKkOFGpWalV#QYX={M(`@A=L5b7trKcF)U;P0MM0&wKo$^iAKA=Rb2y+R`p~2pTrP)5Ap{~V#F3#Wu?9Q}ya>Dnd<^6T92A3z;&(NdWy=@ZD9q>ch)F~okrm=j z0cA0Uh!sSp<*Z8ASdz!>MF)|iB(z~)O1iG&-sbddKWG{kX=Oxi(eMrH8_F=0QOQNq zk|zznGfKLdQE*GoZn~x9iu62VNqWjOnKi?;O?zo;rld%HDB!OG{wCmG0%98EHJH)h zvl`r@!4YjM<*_Z4lOl6WgF7|2SA(VoD;k{F;D;JKrNOT>ctwLt8oZ%QHmNSzM6hIk z(t;&R3-M2l;W{1~1EB@sxqdhngwOQD@gRJ+AI5_4lYSTv!h?OUi6DG1upQ({2Mxa% zALe;)e3U018|66~8|8Tmd?Qa_7r; zOu%gkFcR=+LU{nkw?2SL5t~m!BMB#xU?t%vNktM1Ne)fGEfa8R0-Oo>`Gg{gha_K4 z!Pir8E(MRI;DwYTNrWV~rs0k>bkgud8ZM?4NirlknSpyUu$qDAGw@nQkxYan_f5jN zNqB4$UYdm0ClyI5B>8R@7PIg~7GBB1J6T1N4oS}Cpq+ys<=|ot-p(nKj4DZ-%EP^R z=;h&=Jp48f|IWkVf+Ed^q^ApTUjbGN@N5BoSAc&M;O3$t&4r}jD#Ga^bc=AI2(K35 zKSlULNs;D5(z{D=e+kwu4}Go#moCSjl%P>oq=k_5L>bPM!7am6W%x}QVih=2QKZF? z^nnUAEAagayi|eLD^RGy9aTkI3Q0Rvu&Z#P3a?h--6|ZIf-_T!v>cN9Q}FNKASbvR##U)JIGb@)pi>eFy? zT9Hnv(qwlUR;S_lX?SfK{yYuU88|ZoPtPdwT47xto{#>^yI2^O@FwW+71Aet`dOy zhldJaZf5|lqjU9X-l_A5`cQmvN6xptw)P>0h#FDMM`GA0arUA0h>B2rZHLycuz&4C z8WDAn_)7Hm;mS45K4cM53+;f#|EO#BA&dI|?+aok!usd8vA$8&&FS-l^3GT`&hJA6 zH$)&fv~vWz>OQe6?xTJS96aj<)oojLUD>a}+xpRy$A`{0m-KVWOxeLqw@cqJEpOO7 zb^E6?`O@?C!LaSo-LMtir+2epbj>Jy!=t|W?T-4sb3!f|zPT!|c;+XbyryS Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 2, + fatalErrorCount: 0, + filePath: 'NoPseudoModules.js', + messages: [ + { + column: 2, + fatal: undefined, + line: 2, + message: 'Import of pseudo module \'sap/ui/core/BarColor\'', + messageDetails: 'Import library and reuse the enum from there', + ruleId: 'ui5-linter-no-pseudo-modules', + severity: 2, + }, + { + column: 2, + fatal: undefined, + line: 3, + message: 'Import of pseudo module \'sap/m/ListSeparators\'', + messageDetails: 'Import library and reuse the enum from there', + ruleId: 'ui5-linter-no-pseudo-modules', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: NoPseudoModules_negative.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'NoPseudoModules_negative.js', + messages: [], + warningCount: 0, + }, + ] + ## General: NoPseudoModules/NoPseudoModules.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap b/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap index 2ebbf88bc186b46813989722a4954d92980c7160..56f7529a06b93ed08fa6f71d8b442367c3d0c1f1 100644 GIT binary patch literal 692 zcmV;l0!#ftRzVGL`WviN`~&_1$z(^}i7O$RVqvGc=YE`f z?(+`s*=VeUs&>abe8pDUknhc0=9skz&j#1jlHsJTuBv(xvYB5q(!`==R+TjmHtKa@ z#ZB+CixM_J^2wP4a2&ui6{o0hUTd*Vl#R;eGH3)upi!c8*`ZPgzxgo3wFXgr&x65zHke7sA%_jD3CzTeaek;t6*cj1dlS?+%5jvJ}v-du~ z2cg@8&?omf0WS%7O}(tWJZmRq{gzVJqeR~csQ^Ct#~k3a1KerL+xHBWR_91yQP4Fl$7sn#gKRX|7%ndO?Ls&*rjCbhBM#D`aT0 z>A7ywP_Ag9*8>sP1I>xyz^-z@aS{a$t)k6HbN<;n33;)eg$EOPsuIfBvaZCcvQ=Yc ztH%6~;~Q?XmUjKu+xLvC`%he>>J@41GPi^lR%tU}Tr*=l+|L+q$J`WFw)u|^NzeYP zL%sv>1;8N!&g|47Z|&A0^VYXZgPi#bv9!R>-Z*7nbIde7(ofUsu=x#}->~@&j7blh a-`+OAlRGuaVKW@KX7~f7I^LlJ4gdfKgi3n= literal 658 zcmV;D0&V?4RzVlvWsA!>}$l0 zaXtDNqK1u+VhW}K90f2*)d{McHAbuvm8*Ka4jKXxXqf0sd8oDu;4Xk?0Nw)l3}7Dt zhpFGFdUbJ`TaJS7%klAX&?u-18Y5aDU@wKB$^?zH^a>l%SpgJZgDEEfg7;R>C zu3V9dDDW!k9pOZJ!7GDT6?bIH^TI8ai9K6M6@%%Y28%PcR&?2V%|=#*QBrjW?~4Zz zh64y=3ZD}2oPd`!$U5>_2L=;=@^}DM27umn>^*Yb{QVX<%vcrm1EOTy0JN9V{=CT z$B8Yku#s-<$J=*}Yxq}Ov*smf-2(T75l$QXpK&dX^7u}T@}}ahaB_uz>6rB7pE~9n s0G|LHB;eFe9rMPYI;L-he`uKde?zPoaCLW_b6d0g2F23+QWggQ00)ga@c;k- diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index 542a5af9f..4c951363a 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -4,7 +4,7 @@ The actual snapshot is saved in `linter.ts.snap`. Generated by [AVA](https://avajs.dev). -## General: general/Coverage.js +## General: Coverage.js > Snapshot 1 @@ -92,7 +92,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: general/JSDoc.js +## General: JSDoc.js > Snapshot 1 @@ -126,7 +126,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: general/PlainJS.js +## General: PlainJS.js > Snapshot 1 @@ -169,7 +169,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: general/Raw.js +## General: Raw.js > Snapshot 1 @@ -203,7 +203,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: general/TSLike.js +## General: TSLike.js > Snapshot 1 @@ -237,7 +237,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: general/Undetected.js +## General: Undetected.js > Snapshot 1 @@ -1067,3 +1067,260 @@ Generated by [AVA](https://avajs.dev). warningCount: 0, }, ] + +## General: general/Coverage.js + +> Snapshot 1 + + [ + { + coverageInfo: [ + { + category: 1, + column: 35, + line: 3, + message: 'Unable to analyze this method call because the type of identifier "get" in "oVariantManagementMapDataSelector.get({ reference: sReference })"" could not be determined', + }, + { + category: 1, + column: 4, + line: 6, + message: `Unable to analyze this method call because the type of identifier "forEach" in "oVariantManagement.variants.forEach((oVariant) => {␊ + if (oVariant.visible === false) {␊ + aHiddenVariants.push(oVariant.key);␊ + }␊ + })"" could not be determined`, + }, + { + category: 1, + column: 10, + line: 12, + message: `Unable to analyze this method call because the type of identifier "filter" in "aFlexObjects.filter((oFilteredFlexObject) => {␊ + // The following block should produce a coverage message:␊ + // "Unable to analyze this method call because the type of identifier"␊ + // However, the following line will be transformed to "[...] = ({ [...]" with␊ + // no source map entry for the added brackets (since it does not exist in source).␊ + // This poses a challenge for Reporter.ts to map to the correct location in the source file␊ + const sVariantReference = {␊ + // eslint-disable-next-line camelcase␊ + ctrl_variant: () => (oFilteredFlexObject.getVariantId()),␊ + // eslint-disable-next-line camelcase␊ + ctrl_variant_change: () => (oFilteredFlexObject.getSelector().id),␊ + change: () => (oFilteredFlexObject.getVariantReference())␊ + }[oFilteredFlexObject.getFileType()]?.();␊ + return !aHiddenVariants.includes(sVariantReference);␊ + })"" could not be determined`, + }, + { + category: 1, + column: 30, + line: 18, + message: `Unable to analyze this method call because the type of identifier in "{␊ + // eslint-disable-next-line camelcase␊ + ctrl_variant: () => (oFilteredFlexObject.getVariantId()),␊ + // eslint-disable-next-line camelcase␊ + ctrl_variant_change: () => (oFilteredFlexObject.getSelector().id),␊ + change: () => (oFilteredFlexObject.getVariantReference())␊ + }[oFilteredFlexObject.getFileType()]?.()"" could not be determined`, + }, + { + category: 1, + column: 26, + line: 20, + message: 'Unable to analyze this method call because the type of identifier "getVariantId" in "oFilteredFlexObject.getVariantId()"" could not be determined', + }, + { + category: 1, + column: 33, + line: 22, + message: 'Unable to analyze this method call because the type of identifier "getSelector" in "oFilteredFlexObject.getSelector()"" could not be determined', + }, + { + category: 1, + column: 20, + line: 23, + message: 'Unable to analyze this method call because the type of identifier "getVariantReference" in "oFilteredFlexObject.getVariantReference()"" could not be determined', + }, + { + category: 1, + column: 6, + line: 24, + message: 'Unable to analyze this method call because the type of identifier "getFileType" in "oFilteredFlexObject.getFileType()"" could not be determined', + }, + ], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Coverage.js', + messages: [], + warningCount: 0, + }, + ] + +## General: general/JSDoc.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 2, + fatalErrorCount: 0, + filePath: 'JSDoc.js', + messages: [ + { + column: 5, + fatal: undefined, + line: 15, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 17, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: general/PlainJS.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 3, + fatalErrorCount: 0, + filePath: 'PlainJS.js', + messages: [ + { + column: 3, + fatal: undefined, + line: 6, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 3, + fatal: undefined, + line: 12, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 18, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: general/Raw.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 2, + fatalErrorCount: 0, + filePath: 'Raw.js', + messages: [ + { + column: 5, + fatal: undefined, + line: 9, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 11, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: general/TSLike.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 2, + fatalErrorCount: 0, + filePath: 'TSLike.js', + messages: [ + { + column: 5, + fatal: undefined, + line: 11, + message: 'Use of deprecated property \'blocked\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + { + column: 4, + fatal: undefined, + line: 13, + message: 'Call to deprecated function \'attachTap\' of class \'Button\'', + messageDetails: 'Deprecated test message', + ruleId: 'ui5-linter-no-deprecated-api', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: general/Undetected.js + +> Snapshot 1 + + [ + { + coverageInfo: [ + { + category: 1, + column: 3, + line: 5, + message: `Unable to analyze this method call because the type of identifier "attachTap" in "btn.attachTap(function () {␊ + console.log("Tapped");␊ + })"" could not be determined`, + }, + ], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Undetected.js', + messages: [], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/snapshots/linter.ts.snap b/test/lib/linter/snapshots/linter.ts.snap index fd113b62b90f0a033e34315aef9e0036cb138980..50fa2f593c193c6d0b6f3afe4fc1dbb798f52392 100644 GIT binary patch literal 9660 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 literal 8061 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 LZ=-)cf4KkvVV?9k From d64b365533ff2b2b442fd1e76ba2e42b1cc6380e Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:13:23 +0300 Subject: [PATCH 34/90] fix: Windows paths for tests --- test/lib/linter/_linterHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 29c68394e..dc035d210 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -77,7 +77,7 @@ export function createTestsForFixtures(fixturesPath: string) { fixturesPath, // Needed, because without a namespace, TS's type definition detection // does not function properly for the inheritance case - filePaths: testFiles.map((fileName) => `resources/mycomp/${fileName}`), + filePaths: testFiles.map((fileName) => path.posix.join("resources", "mycomp", fileName)), }); } else { for (const fileName of testFiles) { From c2f2ece07e17f3e336a271de104f699fd98d9514 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:20:35 +0300 Subject: [PATCH 35/90] fix: Paths on windows --- test/lib/linter/_linterHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index dc035d210..42ea7e4c0 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -77,7 +77,7 @@ export function createTestsForFixtures(fixturesPath: string) { fixturesPath, // Needed, because without a namespace, TS's type definition detection // does not function properly for the inheritance case - filePaths: testFiles.map((fileName) => path.posix.join("resources", "mycomp", fileName)), + filePaths: testFiles.map((fileName) => path.join("resources", "mycomp", fileName)), }); } else { for (const fileName of testFiles) { From 292334a6428dbb618cca9c3e2194b097562d1254 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 25 Apr 2024 16:45:21 +0300 Subject: [PATCH 36/90] refactor: Cleanup obsolete code --- src/linter/ui5Types/BestPractices.ts | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index ea322c7a8..ddffd36ce 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -15,13 +15,6 @@ interface AsyncInterfaceFindType { rootViewAsyncFlag: boolean | undefined | null; } -const expectedUIComponentsList = [ - "sap/ui/core/UIComponent", - "sap/ui/generic/app/AppComponent", - "sap/suite/ui/generic/template/lib/AppComponent", - "sap/fe/core/AppComponent", -]; - export default function analyzeComponentJson( node: ts.ExpressionWithTypeArguments, manifestContent: string | undefined, @@ -41,18 +34,8 @@ export default function analyzeComponentJson( return; } - // Gets module dependency's var name - // @ts-expect-error: imports is part of the sourceFile, but is not defined in types - const importsList = parent.imports as ts.Node[]; - const uiComponentImportStatement = importsList.find((importStatement) => - expectedUIComponentsList.includes(importStatement.getText())); - let uiComponentImportVar = "UIComponent"; - if (uiComponentImportStatement && ts.isImportDeclaration(uiComponentImportStatement.parent)) { - uiComponentImportVar = uiComponentImportStatement.parent.importClause?.name?.getText() ?? uiComponentImportVar; - } - if (classDesc && ts.isClassDeclaration(classDesc)) { - const analysisResult = findAsyncInterface(classDesc, manifestContent, checker, uiComponentImportVar); + const analysisResult = findAsyncInterface(classDesc, manifestContent, checker); if (analysisResult) { reportResults(analysisResult, reporter, classDesc); @@ -89,8 +72,7 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy function findAsyncInterface( classDefinition: ts.ClassDeclaration, manifestContent: string | undefined, - checker: ts.TypeChecker, - uiComponentImportVar = "UIComponent" + checker: ts.TypeChecker ): AsyncInterfaceFindType | undefined { if (ts.isClassDeclaration(classDefinition)) { const returnTypeTemplate = { @@ -115,7 +97,7 @@ function findAsyncInterface( // Continue down the heritage chain to search for // the async interface or manifest flags if (ts.isClassDeclaration(declaration) && - declaration?.name?.getText() !== uiComponentImportVar) { + declaration?.name?.getText() !== "UIComponent") { result = findAsyncInterface(declaration, manifestContent, checker) ?? result; } From 5a9aa704d8f46a63965cde37574b1b6b88d20942 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 09:44:26 +0300 Subject: [PATCH 37/90] refactor: Cleanup code --- src/linter/ui5Types/BestPractices.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index ddffd36ce..9a6cff166 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -232,10 +232,7 @@ function reportResults( reporter: SourceFileReporter, classDesc: ts.ClassDeclaration ) { - let hasAsyncInterface: null | undefined | boolean = null; - let routingAsyncFlag: null | undefined | boolean = null; - let rootViewAsyncFlag: null | undefined | boolean = null; - ({hasAsyncInterface, routingAsyncFlag, rootViewAsyncFlag} = analysisResult); + const {hasAsyncInterface, routingAsyncFlag, rootViewAsyncFlag} = analysisResult; if (!hasAsyncInterface) { if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || From 1b1a277ba5e5f852d413c57a2eda7eb08e020a48 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 11:10:41 +0300 Subject: [PATCH 38/90] refactor: Always try to process the manifest --- src/linter/ui5Types/BestPractices.ts | 63 ++++++++++++++-------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 9a6cff166..74412109b 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -143,41 +143,40 @@ function doChecks(metadata: ts.PropertyDeclaration, manifestContent: string | un let rootViewAsyncFlag: boolean | undefined | null = null; let routingAsyncFlag: boolean | undefined | null = null; - if (componentManifest && ts.isPropertyAssignment(componentManifest)) { - // The manifest is an external manifest.json file - if (componentManifest.initializer.getText() === "\"json\"") { - const parsedManifestContent = - JSON.parse(manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; - - const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; - // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef - rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; - routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; - } else if (ts.isObjectLiteralExpression(componentManifest.initializer)) { - /* eslint-disable @typescript-eslint/no-explicit-any */ - const instanceOfPropsRecord = (obj: any): obj is propsRecord => { - return !!obj && typeof obj === "object"; - }; - - const manifestJson = extractPropsRecursive(componentManifest.initializer) ?? {}; - let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; - if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { - manifestSapui5Section = manifestJson["\"sap.ui5\""].value; - } + if (componentManifest && + ts.isPropertyAssignment(componentManifest) && + ts.isObjectLiteralExpression(componentManifest.initializer)) { + /* eslint-disable @typescript-eslint/no-explicit-any */ + const instanceOfPropsRecord = (obj: any): obj is propsRecord => { + return !!obj && typeof obj === "object"; + }; + + const manifestJson = extractPropsRecursive(componentManifest.initializer) ?? {}; + let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; + if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { + manifestSapui5Section = manifestJson["\"sap.ui5\""].value; + } - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && - typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { - rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; - } + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && + typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { + rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; + } - if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && - typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { - routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; - } + if (instanceOfPropsRecord(manifestSapui5Section) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && + instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && + typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { + routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; } + } else { + const parsedManifestContent = + JSON.parse(manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; + + const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; + // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef + rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; + routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; } return { From c410868c2c0574f80bff6f4a0aa332fb51b58804 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 13:39:10 +0300 Subject: [PATCH 39/90] refactor: Detect sap/ui/core/UIComponent dependency --- src/linter/ui5Types/BestPractices.ts | 33 +++++++++++++++++++++------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 74412109b..d9da56cf7 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -34,8 +34,19 @@ export default function analyzeComponentJson( return; } + // @ts-expect-error imports is part of SourceFileObject + const moduleImports = parent.imports as ts.Node[]; + const uiComponentImportVar = moduleImports.reduce((varName: string, importClause: ts.Node) => { + if (ts.isIdentifier(importClause) && importClause.text === "sap/ui/core/UIComponent" && + ts.isImportDeclaration(importClause.parent)) { + varName = importClause.parent?.importClause?.name?.getText() ?? ""; + } + return varName; + }, ""); + if (classDesc && ts.isClassDeclaration(classDesc)) { - const analysisResult = findAsyncInterface(classDesc, manifestContent, checker); + const analysisResult = findAsyncInterface({ + classDefinition: classDesc, manifestContent, checker, uiComponentImportVar}); if (analysisResult) { reportResults(analysisResult, reporter, classDesc); @@ -69,11 +80,12 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy }; } -function findAsyncInterface( - classDefinition: ts.ClassDeclaration, - manifestContent: string | undefined, - checker: ts.TypeChecker -): AsyncInterfaceFindType | undefined { +function findAsyncInterface({classDefinition, manifestContent, checker, uiComponentImportVar}: { + classDefinition: ts.ClassDeclaration; + manifestContent: string | undefined; + checker: ts.TypeChecker; + uiComponentImportVar: string; +}): AsyncInterfaceFindType | undefined { if (ts.isClassDeclaration(classDefinition)) { const returnTypeTemplate = { hasAsyncInterface: null, @@ -97,8 +109,13 @@ function findAsyncInterface( // Continue down the heritage chain to search for // the async interface or manifest flags if (ts.isClassDeclaration(declaration) && - declaration?.name?.getText() !== "UIComponent") { - result = findAsyncInterface(declaration, manifestContent, checker) ?? result; + (!uiComponentImportVar || declaration?.name?.getText() !== uiComponentImportVar)) { + result = findAsyncInterface({ + classDefinition: declaration, + manifestContent, + checker, + uiComponentImportVar, + }) ?? result; } return result; From 95d29c4df5cc88afc8c18a412efc843d58fa74f0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 14:06:40 +0300 Subject: [PATCH 40/90] refactor: Lint Message --- src/linter/ui5Types/BestPractices.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index d9da56cf7..7603a0a18 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -270,7 +270,7 @@ function reportResults( node: classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag for \"sap.ui5/rootView\" from the manifest", + message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. Remove the async flag for \"sap.ui5/rootView\" from the manifest", messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } @@ -279,7 +279,7 @@ function reportResults( node: classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", + message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. Remove the async flag for \"sap.ui5/routing/config\" from the manifest", messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } From 52dd0d53ab23a97066e5f409d137558f29144a63 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 14:14:52 +0300 Subject: [PATCH 41/90] fix: Update messages & tests --- src/linter/ui5Types/BestPractices.ts | 6 +- .../rules/snapshots/BestPractices.ts.md | 12 +- .../rules/snapshots/BestPractices.ts.snap | Bin 1285 -> 1299 bytes .../rules/snapshots/CSPCompliance.ts.md | 76 - .../rules/snapshots/CSPCompliance.ts.snap | Bin 876 -> 821 bytes .../rules/snapshots/NoDeprecatedApi.ts.md | 1243 ----------------- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 12789 -> 6736 bytes .../linter/rules/snapshots/NoGlobals.ts.md | 175 --- .../linter/rules/snapshots/NoGlobals.ts.snap | Bin 1699 -> 1596 bytes .../rules/snapshots/NoPseudoModules.ts.md | 49 - .../rules/snapshots/NoPseudoModules.ts.snap | Bin 692 -> 657 bytes test/lib/linter/snapshots/linter.ts.md | 257 ---- test/lib/linter/snapshots/linter.ts.snap | Bin 9660 -> 8056 bytes 13 files changed, 10 insertions(+), 1808 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 7603a0a18..7abbf5f54 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -270,7 +270,8 @@ function reportResults( node: classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. Remove the async flag for \"sap.ui5/rootView\" from the manifest", + message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + + "Remove the async flag for \"sap.ui5/rootView\" from the manifest", messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } @@ -279,7 +280,8 @@ function reportResults( node: classDesc, severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", - message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. Remove the async flag for \"sap.ui5/routing/config\" from the manifest", + message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + + "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 0a5aa9137..6c4d44cb5 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -150,7 +150,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, @@ -159,7 +159,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, @@ -209,7 +209,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, @@ -218,7 +218,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, @@ -243,7 +243,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/rootView" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, @@ -252,7 +252,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Remove the async flag for "sap.ui5/routing/config" from the manifest', + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', severity: 1, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 067087b3eaceafc41f1366d98c2e92f1db9f2aac..077f3c8934e2c17e9d78cb010fb1a62b631fd161 100644 GIT binary patch literal 1299 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 diff --git a/test/lib/linter/rules/snapshots/CSPCompliance.ts.md b/test/lib/linter/rules/snapshots/CSPCompliance.ts.md index dbc40c6ee..14c91c621 100644 --- a/test/lib/linter/rules/snapshots/CSPCompliance.ts.md +++ b/test/lib/linter/rules/snapshots/CSPCompliance.ts.md @@ -79,79 +79,3 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [] - -## General: CSPCompliance/NoInlineJS.html - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'NoInlineJS.html', - messages: [ - { - column: 2, - fatal: undefined, - line: 9, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - { - column: 2, - fatal: undefined, - line: 17, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - { - column: 2, - fatal: undefined, - line: 25, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - { - column: 2, - fatal: undefined, - line: 31, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - { - column: 2, - fatal: undefined, - line: 47, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - { - column: 2, - fatal: undefined, - line: 55, - message: 'Use of unsafe inline script', - messageDetails: 'Content Security Policy (https://ui5.sap.com/1.120/#/topic/fe1a6dba940e479fb7c3bc753f92b28c)', - ruleId: 'ui5-linter-csp-unsafe-inline-script', - severity: 1, - }, - ], - warningCount: 6, - }, - ] - -## General: CSPCompliance/NoInlineJS_negative.html - -> Snapshot 1 - - [] diff --git a/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap b/test/lib/linter/rules/snapshots/CSPCompliance.ts.snap index d5ca286a37f4ffa9c5cbc3eec0550d66855256c8..c5a1b68803b565e1a39e1f549050ae567cb0c382 100644 GIT binary patch literal 821 zcmV-51IqkCRzVkX*YRAmmd8Kn`<@u|e z?&^9ji64sy00000000B+m%ncuMHI(B@AmfBos+W@3VswExB!&gUF^g$jt~+G2$>>S ziikjpi01ZY?G5YQV|UJpk&qxIe*g^~Jk@Rz`%iP4t(suO$UB;;HnEZ-HP3vvj5=1k1qV_!lNFX_TX&~ zekrtHv3pbY3qD-*;T<17^x=jNKl?Cjz>P-5?oZjjZNT>p_^km)n$T@R)P%c*o~zg! zQ|0bf>cRxiqR?DH!zcU-NL`D3r;x}ApYQIe}rx1+Mu z+j)>hLsPLH9$R13Mn!QxS-yBSO^i-V`@9ZDS!8zG8)+N`yX~j9j2Y%HL4rS8)5iQZz*q{Arag?dSy9`x1PsT2Ct>RQ-e4Nmrh)s>Us+H!yS+2ENflWY|0 z^}%GiIEq#}ag-RHb%K1@xtB!eUJ{*slkjrAql;IL`N;pseqqM`z}P=BV}D@mAD^*5 zF!sF}`vYUYI%EIu>?bYA6Z^CvmlD0HOtho-??ql;{JRzT#}4E#$uL$v>JoSo zgSX%#Dj$mo00000000B+m(6bsVI0T5znz`8-Lh>tcsW>_cnQ0srK%zlDUmwRq#-0i zo}GQBeVCnDGtZVvB#4tgz(pb1=T!6`eVKpO^3R z@_Bxl6Mz8#OGxV>b$1Z3X`)1xN+nPMM4%$k&cvjj0dO9`H2@C*yav!q zz$R)hq#dlCTjO_021}y?Zlv(@?(r*!Pmw@{OJR;x;0nZ3{MYF-@)8Mrj{9B5_7l}6Jki5ppNakXBCz47m z-$XJW%XJDsYP7%MD1fT~R}|p30z6iL&kArM4?NDN-b|hSW(FCr^T3-tpsBzb71*T$ z(<<;O(pt){b=Z$anExAaA+v3yjnZJ(JM)7#aWv{xPqdD(Z$EiYsaFN?U; z%b^{Jrc7BEx2=1)WWo)T?qegqC%Grf*d{@}h<@J+NHp3m3)e?i%kTt8e z->~|t{R5k=K1=#dVOtLGXWQyEHoSE+-#Rqx)Q0RWHG61qi!(e>8`y4dNHYmqE+4HY z&AyfxthmCHJgC@Vv-0f{m2a1*%y|hT{n&%=Z(FU zv7a~gLmB&Dvri((>Nz6F36D=ODW>?`S>#CH_bBqy1d^=3c4qyN@v#xV(R2m#Y;I+N zCks4T;K>5dg8m6-f#<(up9P*Q@GM03S>VY6&p*pP2_)8U1IeF=KVJc*q0;N?82|uj CeVkVS diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index 7e682f1ef..9880d65ff 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -1246,1246 +1246,3 @@ Generated by [AVA](https://avajs.dev). warningCount: 0, }, ] - -## General: NoDeprecatedApi/ModuleImport.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'ModuleImport.js', - messages: [ - { - column: 16, - fatal: undefined, - line: 1, - message: 'Import of deprecated module \'sap/ui/model/odata/ODataModel\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/NoDeprecatedApi.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 17, - fatalErrorCount: 0, - filePath: 'NoDeprecatedApi.js', - messages: [ - { - column: 18, - fatal: undefined, - line: 2, - message: 'Import of deprecated module \'sap/m/DateTimeInput\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 41, - fatal: undefined, - line: 2, - message: 'Import of deprecated module \'sap/base/util/includes\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 107, - fatal: undefined, - line: 2, - message: 'Import of deprecated module \'sap/ui/generic/app/navigation/service/NavigationHandler\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 9, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 10, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 13, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'plugins\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 21, - message: 'Use of deprecated property \'groupBy\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 24, - message: 'Call to deprecated function \'includes\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 26, - message: 'Call to deprecated function \'getCompatibilityVersion\' of class \'Configuration\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 27, - message: 'Call to deprecated function \'getCompatibilityVersion\' of class \'Configuration\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 29, - message: 'Access of deprecated property \'webview\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 30, - message: 'Access of deprecated property \'webview\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 32, - message: 'Access of deprecated property \'AnimationMode\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 34, - message: 'Access of deprecated property \'MessageType\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 36, - message: 'Access of deprecated property \'Date\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 39, - message: 'Call to deprecated function \'storeInnerAppState\' of class \'NavigationHandler\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/NoDeprecatedApi_negative.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'NoDeprecatedApi_negative.js', - messages: [], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/PartialDeprecation.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'PartialDeprecation.js', - messages: [], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/PrototypeClass.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'PrototypeClass.js', - messages: [ - { - column: 3, - fatal: undefined, - line: 10, - message: 'Call to deprecated function \'setVisibleRowCount\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLFragment.fragment.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 6, - fatalErrorCount: 0, - filePath: 'XMLFragment.fragment.xml', - messages: [ - { - column: 2, - fatal: undefined, - line: 6, - message: 'Import of deprecated module \'sap/m/DateTimeInput\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 10, - fatal: undefined, - line: 8, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 15, - fatal: undefined, - line: 10, - message: 'Use of deprecated property \'groupBy\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 11, - message: 'Use of deprecated property \'plugins\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 11, - fatal: undefined, - line: 17, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 17, - message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLFragmentDefinition.fragment.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 6, - fatalErrorCount: 0, - filePath: 'XMLFragmentDefinition.fragment.xml', - messages: [ - { - column: 2, - fatal: undefined, - line: 7, - message: 'Import of deprecated module \'sap/m/DateTimeInput\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 10, - fatal: undefined, - line: 9, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 15, - fatal: undefined, - line: 11, - message: 'Use of deprecated property \'groupBy\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 12, - message: 'Use of deprecated property \'plugins\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 11, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLHtmlSvg.view.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 4, - fatalErrorCount: 0, - filePath: 'XMLHtmlSvg.view.xml', - messages: [ - { - column: 1, - line: 6, - message: 'Usage of native HTML in XML Views/Fragments is deprecated', - messageDetails: '{@link topic:be54950cae1041f59d4aa97a6bade2d8 Using Native HTML in XML Views (deprecated)}', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 1, - line: 8, - message: 'Usage of SVG in XML Views/Fragments is deprecated', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 2, - line: 9, - message: 'Usage of SVG in XML Views/Fragments is deprecated', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - line: 10, - message: 'Usage of SVG in XML Views/Fragments is deprecated', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLRequire.view.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'XMLRequire.view.xml', - messages: [ - { - column: 2, - fatal: undefined, - line: 4, - message: 'Import of deprecated module \'sap/ui/core/Message\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLTemplatingRequire.view.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 2, - fatalErrorCount: 0, - filePath: 'XMLTemplatingRequire.view.xml', - messages: [ - { - column: 2, - fatal: undefined, - line: 6, - message: 'Import of deprecated module \'sap/ui/core/Message\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 8, - fatal: undefined, - line: 9, - message: 'Import of deprecated module \'sap/ui/model/odata/ODataModel\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/XMLView.view.xml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 6, - fatalErrorCount: 0, - filePath: 'XMLView.view.xml', - messages: [ - { - column: 2, - fatal: undefined, - line: 7, - message: 'Import of deprecated module \'sap/m/DateTimeInput\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 10, - fatal: undefined, - line: 9, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 15, - fatal: undefined, - line: 11, - message: 'Use of deprecated property \'groupBy\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 12, - message: 'Use of deprecated property \'plugins\' of class \'Table\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 11, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'buttons\' of class \'SegmentedButton\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/jQuery-device.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 3, - fatalErrorCount: 0, - filePath: 'jQuery-device.js', - messages: [ - { - column: 15, - fatal: undefined, - line: 2, - message: 'Access of deprecated property \'device\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 11, - fatal: undefined, - line: 3, - message: 'Access of deprecated property \'os\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - { - column: 18, - fatal: undefined, - line: 4, - message: 'Access of deprecated property \'os\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-property', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/jQuery-plugins.js - -> Snapshot 1 - - [ - { - coverageInfo: [ - { - category: 1, - column: 18, - line: 3, - message: 'Unable to analyze this method call because the type of identifier "outerHTML" in "jQuery("#button").outerHTML()"" could not be determined', - }, - { - category: 1, - column: 2, - line: 4, - message: 'Unable to analyze this method call because the type of identifier "root" in "jQuery("#content").root({})"" could not be determined', - }, - { - category: 1, - column: 15, - line: 5, - message: 'Unable to analyze this method call because the type of identifier "uiarea" in "jQuery("#content").uiarea(0)"" could not be determined', - }, - ], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'jQuery-plugins.js', - messages: [ - { - column: 16, - fatal: undefined, - line: 2, - message: 'Call to deprecated function \'control\' of class \'JQueryStatic\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/jQuery.sap.js - -> Snapshot 1 - - [ - { - coverageInfo: [ - { - category: 1, - 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: 9, - fatalErrorCount: 0, - filePath: 'jQuery.sap.js', - messages: [ - { - 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, - }, - { - 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: '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, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/library.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 11, - fatalErrorCount: 0, - filePath: 'library.js', - messages: [ - { - column: 2, - fatal: undefined, - line: 9, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 10, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 11, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 12, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 16, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 19, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 22, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 25, - message: 'Call to Library.init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 30, - message: 'Call to LibInit() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 35, - message: 'Call to init() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 40, - message: 'Call to intRenames() must be declared with property {apiVersion: 2}', - messageDetails: 'Lib.init (https://ui5.sap.com/1.120/#/api/sap.ui.core.Lib)', - ruleId: 'ui5-linter-no-partially-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/library_negative.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'library_negative.js', - messages: [], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/manifest.json - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 23, - fatalErrorCount: 0, - filePath: 'manifest.json', - messages: [ - { - column: 17, - fatal: undefined, - line: 47, - message: 'Use of deprecated library \'sap.ca.scfld.md\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 48, - message: 'Use of deprecated library \'sap.ca.ui\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 49, - message: 'Use of deprecated library \'sap.fe.common\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 50, - message: 'Use of deprecated library \'sap.fe.plugins\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 51, - message: 'Use of deprecated library \'sap.fe.semantics\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 52, - message: 'Use of deprecated library \'sap.landvisz\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 53, - message: 'Use of deprecated library \'sap.makit\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 54, - message: 'Use of deprecated library \'sap.me\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 55, - message: 'Use of deprecated library \'sap.sac.grid\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 56, - message: 'Use of deprecated library \'sap.ui.commons\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 57, - message: 'Use of deprecated library \'sap.ui.suite\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 58, - message: 'Use of deprecated library \'sap.ui.ux3\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 59, - message: 'Use of deprecated library \'sap.ui.vtm\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 60, - message: 'Use of deprecated library \'sap.uiext.inbox\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 61, - message: 'Use of deprecated library \'sap.webanalytics.core\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 62, - message: 'Use of deprecated library \'sap.zen.commons\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 63, - message: 'Use of deprecated library \'sap.zen.crosstab\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 64, - message: 'Use of deprecated library \'sap.zen.dsh\'', - ruleId: 'ui5-linter-no-deprecated-library', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 67, - message: 'Use of deprecated component \'sap.zen.dsh.fioriwrapper\'', - ruleId: 'ui5-linter-no-deprecated-component', - severity: 2, - }, - { - column: 13, - fatal: undefined, - line: 79, - message: 'Use of deprecated property \'sap.ui5/resources/js\'', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 21, - fatal: undefined, - line: 92, - message: 'Use of deprecated property \'sap.ui5/models/odata-v4/settings/synchronizationMode\' of sap.ui.model.odata.v4.ODataModel', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 21, - fatal: undefined, - line: 98, - message: 'Use of deprecated property \'sap.ui5/models/odata-v4-via-dataSource/settings/synchronizationMode\' of sap.ui.model.odata.v4.ODataModel', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 17, - fatal: undefined, - line: 102, - message: 'Use of deprecated model type \'sap.ui5/models/odata/type="sap.ui.model.odata.ODataModel"\'', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/manifest_negative.json - -> Snapshot 1 - - [] - -## General: NoDeprecatedApi/manifest_negative_empty.json - -> Snapshot 1 - - [] - -## General: NoDeprecatedApi/sap.ui.jsview.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'sap.ui.jsview.js', - messages: [ - { - column: 1, - fatal: undefined, - line: 1, - message: 'Call to deprecated function \'jsview\' (sap.ui.jsview)', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/sap.ui.require-nested.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'sap.ui.require-nested.js', - messages: [ - { - column: 6, - fatal: undefined, - line: 6, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/sap.ui.require-toplevel.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'sap.ui.require-toplevel.js', - messages: [ - { - column: 3, - fatal: undefined, - line: 3, - message: 'Use of deprecated property \'tap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoDeprecatedApi/ui5.yaml - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'ui5.yaml', - messages: [ - { - column: 7, - fatal: undefined, - line: 11, - message: 'Use of deprecated library \'sap.landvisz\'', - ruleId: 'ui5-linter-no-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 4eb8d2802f1aec0455636090d5bca53e6d485954..1b59165a3fed7e39b22cf37a8483e0ac9ce4a3b8 100644 GIT binary patch literal 6736 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 Snapshot 1 - - [ - { - coverageInfo: [ - { - category: 1, - column: 4, - line: 9, - message: 'Unable to analyze this method call because the type of identifier "helperFunction" in "cust.lib.helperFunction()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 14, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "sap.ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 15, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "window["sap"].ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 16, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "window.sap.ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 17, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "globalThis.sap.ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 18, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "self.sap.ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 20, - message: 'Unable to analyze this method call because the type of identifier "requireSync" in "that.sap.ui.requireSync()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 29, - message: 'Unable to analyze this method call because the type of identifier "require" in "jQuery.sap.require()"" could not be determined', - }, - { - category: 1, - column: 4, - line: 32, - message: 'Unable to analyze this method call because the type of identifier "stub" in "sinon.stub()"" could not be determined', - }, - ], - errorCount: 11, - fatalErrorCount: 0, - filePath: 'NoGlobals.js', - messages: [ - { - column: 8, - fatal: undefined, - line: 8, - message: 'Access of global variable \'sap\' (sap.m.Button)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 19, - fatal: undefined, - line: 11, - message: 'Access of global variable \'sap\' (sap.m)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 14, - message: 'Access of global variable \'sap\' (sap.ui.requireSync)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 15, - message: 'Access of global variable \'sap\' (window)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 16, - message: 'Access of global variable \'sap\' (window.sap.ui.requireSync)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 18, - message: 'Access of global variable \'sap\' (self.sap.ui.requireSync)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 20, - message: 'Access of global variable \'sap\' (that.sap.ui.requireSync)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 25, - message: 'Access of global variable \'sap\' (window)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 27, - message: 'Access of global variable \'jQuery\' (jQuery.ajax)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 28, - message: 'Access of global variable \'jQuery\' (jQuery)', - ruleId: 'ui5-linter-no-globals-js', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 29, - message: 'Use of deprecated API \'jQuery.sap.require\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoGlobals/NoGlobals_Negative.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'NoGlobals_Negative.js', - messages: [], - warningCount: 0, - }, - ] diff --git a/test/lib/linter/rules/snapshots/NoGlobals.ts.snap b/test/lib/linter/rules/snapshots/NoGlobals.ts.snap index 5e4af53f9f7bb5b31b32880f5aeeb96bf5c8e384..c0d1f72e1a43d6ecd084b90d647a64a45eef7079 100644 GIT binary patch literal 1596 zcmV-C2E+M5RzVR-@Gt++-) zs;JstG&|m1>@%syiekkUd-cva=Xc)uJ!f{#yL(<;Y+6q1d)^ZlrEmI{>>ZP~bPelk z`U&TlS z3-K?F;W{1~1EB@sxqdhngwOTE@gRJ+AI5_4lYSTv!h?OUi6DG1upQ({2Ms?TALe;~ ze3U018|66~8|8U4Hp=t6*eK7(u~D9d_$W^&zL6&_#IO3{hN-{y!&Dzx>_7rOpMcvE zU?kwNgz^B6Z+!rhA~v6dMiNdW!Aio@NktM1Ne)fG%@c5H0-Oo>>4YMQha|V8;2SA8 zmx4!A@N!C#Btnu~({M)`I%#+^4HwgjBpH&N%)qxZu$qAvGw?=6kxYan_f5jNNqBq` zUYUfqClyI5BzY(ci&=Ow3$JD2ovb2Bha~56(9Xe+a&R#Rf66J6j4DZ-%EP^R=;h(L zJp3jP|H;GQf+Ed^q^ApTUjbGN@O%M&TY!HS;HIJ?&4r|Q7U6Uex<$B9gx8Dk-y(de zq)782={+U5zXWTShrUpPOPAwMO3)}P(n3gjq6}xs;FjUpGW@y>u?ifiDAHm``alJm z75IJyUa7#_6)05Uj;bOpg`}M-*j2bth1aX_ZWRtp!I>#VS`JD5DR^WGUY>%trri*F(e7WSf>w{fLDE;x4WA#?-L9ePF zw@h0O`X-dV#9*r#Tx&n!tZg(csr!y@*oL+Kh}8X#>FF!d?>KF}WmuNplr5v@^*f~Q zuXm;HEb3-k+P=AHN>`ulNUJN|Z}se!Z#wp@Zrb{6tLOO*%WO8bcFx~8JFB;xp4HZE z$Jd)uZ%bdgE2b^myNn_mf#Qj4fx?v!_e@vbvu?LGICw_4(K8#H+OH#mTm*s(yMkcN zwA;?wcls!1AKW`I@)0n8yo)dzd+M<$M38u9S4b=c1@W1V>Fq5V#RwWt?aq5bT8n#& zL;1RJ@H>XTw>TWwo`ZP&+F{s0uzac~-Sq&%p#3_!*CX6}*TB8!_nL!mfoVH-qkkP~ zIlir>q|zG;ezyl#iOFs3syfwf<7lfTJ+JRzPfi z8`XPsdzL)j9$waZ=2sRh)ApsiU^@#N6M75F>i+;qPp(SW^oOgd?EpaODgmf}c&Gs8 zb_U=&I#-|OojQ-G55<>v&)_laF`AN5<{;8`!IZrif!%6<*r){mY%K6Jjhq@Pn}$_{3_UHXP;dBf(Z+drMj zm!7W=hHa1ThOOv6y_*H2YewN4obR3gT=;w5;hU@SiYI;InQMB|_XptbKuy5m uou2faz1ovL^$71O5Be%sWEI@n!&iUex7|VBmcH>#eg6Z`%J9vx9RL8EO&VAL literal 1699 zcmV;U23+|;RzV1@yY00000000B+ncHt1R~^ScXY9Rr*WQcw;$6Fek&&>Q)C&zDafy)97Sc#G zP12+nK?Ae9$KEmH8FyyZj;prfQk7d;=tZcAzBKfqLV{GNQmYCO59O%{@fUyu;u#4E z6#)-q$GcnmOz@Z}R%~_l={IxE_x$GfIkPjr-S5kbP0MM0)qC=?^iAKA-4oK5u3>#z zKjoaToTg!Ujb+dDY-82yIKKDwm)mW_Hy)a~GD3>pN2G;z8*mgTiDXeEj=Qe0A;cic z=ktgRLLjn292%il{kAYtSe*p>t4vYRm$$Oj2vgHeH7#0cz!~`OV$O&gC_QFgLS>jL%K9qtx zQ(&av@sx4{j&8pJ(;_jShDI7rrNK(Wx6_Iw5t1AkgWJd8%osRh@Vzlbk_<^cnSsw{ z;6er-%fO2nMUo0h?#RO3S?FZpsVrR1Dw1?aa(W!@ABVMZcwrn~8&@P_A<2UiaA5+T zn1Gii;LQm|k_kz^l7qz@Je7l2a`2m+BFTm%7xK`~!;^WqoQGfM70I|NNu4Rc0|n?7 z;MoHFtN{Nmz|o>2&4r|Ai|}9(){5|45q@5Te-z=iNky6uNxv`&XD4BG5-v@`tCR4b zN%&YvkrqPI`%3Uo3D&PpeZB-&uEy_{pix$&#gOz=8P1i#EyFWq_-Ppu6*yK=q>~}( zmnzV#z}G79QU%_uK(PvUR~2a~B<)neuEM1%yjq2~t8i!v&P^%Oa!Be=!J|{~;uO3- z1%J32*J^NYO_5eYQl|#ptJ9vZ!Ic`kQ-hg0oUJR;YDntV;bI+rSchNK;rDf@Ps8bH zMLMNQ)2q|4HVrRK!)w#ieT*_;Sf{H~McOp^PV6j@4bU z`=hFQ)G}?^9~)D~QvFv=|5*Dj=WU~DN!@pJ!#1pqN2Ts}Oiy2te#dF+EyJ?(rfeBq zuQwode`8hZ&Z2I%rR|%GrgZh$jTT&ucg3`2dyi4%B2aweMxb!zBVE&#_ifm%O%9&1+US~%E$43{f_wym zOM8M~-L%`z`WJgBW*^=^FbWYczO#og8vE+DC`OQYdQV6!1r71Jj_K_$8j}$;zO^^c z3280vFAn9K!olwt{{G@{XlD-Mi5rJu6T$MCu5>p72>tUnv3fnCdhZ5Q@A=(k|65?% zj@{@TN0yx2v81#znh1Wk2S=%i9m-X8YPpT$t(Nq>UIm-aFMZ8$&49q1XROZY^Sy0b zY24BEeaF64y+*fd$&>BDVXbR^V!<+PU%Csnv#`0Kx3H}K50LicnsiNnu$$U00FfOBC$|L$i@$p?%zWuRv05L@Lh+;kx!)A+f085YP2*qc1S^72J zUk8vzL?0wR75#mTs>&H)@98|uwrJqw)%Jo;eOZtXs zd4tnacfGfgFFjxHPum&YE!)w(cQp&fsu_i^@9$mwK-l2>@+rAw_~x3trqd^$zM)Rv zFM&S;H33I=>-3$!UZ+pB@UGM7t6Y;+aA}WRzvH))k+*GZbj#RaA3qr0$B)F8ZEV@b zmThd=#+Get*~XS_Y}v+^ZEV@bmThd=#+Get*~XS_Y}v+^?VkK88C$lyyPIRn_W!~V tTeh)f8(X%qWgA Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 2, - fatalErrorCount: 0, - filePath: 'NoPseudoModules.js', - messages: [ - { - column: 2, - fatal: undefined, - line: 2, - message: 'Import of pseudo module \'sap/ui/core/BarColor\'', - messageDetails: 'Import library and reuse the enum from there', - ruleId: 'ui5-linter-no-pseudo-modules', - severity: 2, - }, - { - column: 2, - fatal: undefined, - line: 3, - message: 'Import of pseudo module \'sap/m/ListSeparators\'', - messageDetails: 'Import library and reuse the enum from there', - ruleId: 'ui5-linter-no-pseudo-modules', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: NoPseudoModules/NoPseudoModules_negative.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'NoPseudoModules_negative.js', - messages: [], - warningCount: 0, - }, - ] diff --git a/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap b/test/lib/linter/rules/snapshots/NoPseudoModules.ts.snap index 56f7529a06b93ed08fa6f71d8b442367c3d0c1f1..7c19573fcf8e1f2eec3b7d8f169fe6f1a9d4779a 100644 GIT binary patch literal 657 zcmV;C0&e|5RzVzx&?dQ?)~;NuvAMa&xHK4v zc7~-a7axlV00000000Bkls#_~K@f)DxjWmZeAyw0CJ0@DlqQb(5CS0@2na>uBT__x zDA2|p+Z*n7&F-E<3JNHYC=dk=5)x9VXsBqRpyW4D0pbtv3s5dTz!!{AAO%Y_G<;dCT5^!A`oE@629g#YV)ZqbqvZa@x|Dbt{e8F05H;mFU^7cJ|(8t0kPc z9(?ps!PZA1dGi2{0hpokG?mU8BQ}WgRkd0Lje!U>PIM+eR9Odb7r-+BZvlJ;aDad# zG-y=5y1K?qN8a~ktyTj~g36#Nq7?%6lMgCQ(?nDE*@zA=skR1HF+*OyH^#)l93dhSkl&cgll$$zE6E#AYQl?85RVE92K`a%I zI9C}!&*O!qq^FIGbUW&0f<;NDSTtuvuaU||QyXra6J}Az+RPQYO%1x8XD4KA^Yr|n zX)ITbFdLCjt;ld{IdWZ&SfxqSHagjg3>Tkm(wLW8d3Z3DC+e|Oj!j+Z`u2?V?HP+d zPH4H$M!Jn3Z{IVn{$FuT8keMXE8G)CIBo2I#x*y_!=sGxrs9rpvd_PCNP6;59r6u; rPXG=PaOzJT^2Tl*vS@v~G|1WC5X%N!-y5eKX^!6jqok)B_67g|fUquK literal 692 zcmV;l0!#ftRzVGL`WviN`~&_1$z(^}i7O$RVqvGc=YE`f z?(+`s*=VeUs&>abe8pDUknhc0=9skz&j#1jlHsJTuBv(xvYB5q(!`==R+TjmHtKa@ z#ZB+CixM_J^2wP4a2&ui6{o0hUTd*Vl#R;eGH3)upi!c8*`ZPgzxgo3wFXgr&x65zHke7sA%_jD3CzTeaek;t6*cj1dlS?+%5jvJ}v-du~ z2cg@8&?omf0WS%7O}(tWJZmRq{gzVJqeR~csQ^Ct#~k3a1KerL+xHBWR_91yQP4Fl$7sn#gKRX|7%ndO?Ls&*rjCbhBM#D`aT0 z>A7ywP_Ag9*8>sP1I>xyz^-z@aS{a$t)k6HbN<;n33;)eg$EOPsuIfBvaZCcvQ=Yc ztH%6~;~Q?XmUjKu+xLvC`%he>>J@41GPi^lR%tU}Tr*=l+|L+q$J`WFw)u|^NzeYP zL%sv>1;8N!&g|47Z|&A0^VYXZgPi#bv9!R>-Z*7nbIde7(ofUsu=x#}->~@&j7blh a-`+OAlRGuaVKW@KX7~f7I^LlJ4gdfKgi3n= diff --git a/test/lib/linter/snapshots/linter.ts.md b/test/lib/linter/snapshots/linter.ts.md index 4c951363a..0e377b7b8 100644 --- a/test/lib/linter/snapshots/linter.ts.md +++ b/test/lib/linter/snapshots/linter.ts.md @@ -1067,260 +1067,3 @@ Generated by [AVA](https://avajs.dev). warningCount: 0, }, ] - -## General: general/Coverage.js - -> Snapshot 1 - - [ - { - coverageInfo: [ - { - category: 1, - column: 35, - line: 3, - message: 'Unable to analyze this method call because the type of identifier "get" in "oVariantManagementMapDataSelector.get({ reference: sReference })"" could not be determined', - }, - { - category: 1, - column: 4, - line: 6, - message: `Unable to analyze this method call because the type of identifier "forEach" in "oVariantManagement.variants.forEach((oVariant) => {␊ - if (oVariant.visible === false) {␊ - aHiddenVariants.push(oVariant.key);␊ - }␊ - })"" could not be determined`, - }, - { - category: 1, - column: 10, - line: 12, - message: `Unable to analyze this method call because the type of identifier "filter" in "aFlexObjects.filter((oFilteredFlexObject) => {␊ - // The following block should produce a coverage message:␊ - // "Unable to analyze this method call because the type of identifier"␊ - // However, the following line will be transformed to "[...] = ({ [...]" with␊ - // no source map entry for the added brackets (since it does not exist in source).␊ - // This poses a challenge for Reporter.ts to map to the correct location in the source file␊ - const sVariantReference = {␊ - // eslint-disable-next-line camelcase␊ - ctrl_variant: () => (oFilteredFlexObject.getVariantId()),␊ - // eslint-disable-next-line camelcase␊ - ctrl_variant_change: () => (oFilteredFlexObject.getSelector().id),␊ - change: () => (oFilteredFlexObject.getVariantReference())␊ - }[oFilteredFlexObject.getFileType()]?.();␊ - return !aHiddenVariants.includes(sVariantReference);␊ - })"" could not be determined`, - }, - { - category: 1, - column: 30, - line: 18, - message: `Unable to analyze this method call because the type of identifier in "{␊ - // eslint-disable-next-line camelcase␊ - ctrl_variant: () => (oFilteredFlexObject.getVariantId()),␊ - // eslint-disable-next-line camelcase␊ - ctrl_variant_change: () => (oFilteredFlexObject.getSelector().id),␊ - change: () => (oFilteredFlexObject.getVariantReference())␊ - }[oFilteredFlexObject.getFileType()]?.()"" could not be determined`, - }, - { - category: 1, - column: 26, - line: 20, - message: 'Unable to analyze this method call because the type of identifier "getVariantId" in "oFilteredFlexObject.getVariantId()"" could not be determined', - }, - { - category: 1, - column: 33, - line: 22, - message: 'Unable to analyze this method call because the type of identifier "getSelector" in "oFilteredFlexObject.getSelector()"" could not be determined', - }, - { - category: 1, - column: 20, - line: 23, - message: 'Unable to analyze this method call because the type of identifier "getVariantReference" in "oFilteredFlexObject.getVariantReference()"" could not be determined', - }, - { - category: 1, - column: 6, - line: 24, - message: 'Unable to analyze this method call because the type of identifier "getFileType" in "oFilteredFlexObject.getFileType()"" could not be determined', - }, - ], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'Coverage.js', - messages: [], - warningCount: 0, - }, - ] - -## General: general/JSDoc.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 2, - fatalErrorCount: 0, - filePath: 'JSDoc.js', - messages: [ - { - column: 5, - fatal: undefined, - line: 15, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 17, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: general/PlainJS.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 3, - fatalErrorCount: 0, - filePath: 'PlainJS.js', - messages: [ - { - column: 3, - fatal: undefined, - line: 6, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 3, - fatal: undefined, - line: 12, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 18, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: general/Raw.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 2, - fatalErrorCount: 0, - filePath: 'Raw.js', - messages: [ - { - column: 5, - fatal: undefined, - line: 9, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 11, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: general/TSLike.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 2, - fatalErrorCount: 0, - filePath: 'TSLike.js', - messages: [ - { - column: 5, - fatal: undefined, - line: 11, - message: 'Use of deprecated property \'blocked\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - { - column: 4, - fatal: undefined, - line: 13, - message: 'Call to deprecated function \'attachTap\' of class \'Button\'', - messageDetails: 'Deprecated test message', - ruleId: 'ui5-linter-no-deprecated-api', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: general/Undetected.js - -> Snapshot 1 - - [ - { - coverageInfo: [ - { - category: 1, - column: 3, - line: 5, - message: `Unable to analyze this method call because the type of identifier "attachTap" in "btn.attachTap(function () {␊ - console.log("Tapped");␊ - })"" could not be determined`, - }, - ], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'Undetected.js', - messages: [], - warningCount: 0, - }, - ] diff --git a/test/lib/linter/snapshots/linter.ts.snap b/test/lib/linter/snapshots/linter.ts.snap index 50fa2f593c193c6d0b6f3afe4fc1dbb798f52392..fdcc391c8ee5db69fe3725b552ba70010cd88341 100644 GIT binary patch literal 8056 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 From 5338f9cceeadba6abc2ea9cc5bf338c452716a2f Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 14:38:50 +0300 Subject: [PATCH 42/90] feat: Detect manifest.json section in Component.js --- src/linter/ui5Types/BestPractices.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 7abbf5f54..907a8c30c 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -11,6 +11,7 @@ type propsRecord = Record Date: Fri, 26 Apr 2024 14:55:45 +0300 Subject: [PATCH 43/90] fix: Detect missing manifest declaration in Component.js --- src/linter/ui5Types/BestPractices.ts | 5 +- .../BestPractices/Positive_6/Component.js | 9 ++++ .../BestPractices/Positive_6/manifest.json | 45 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.md | 25 ++++++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 1299 -> 1418 bytes 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_6/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 907a8c30c..e94218919 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -200,7 +200,10 @@ function doChecks(metadata: ts.PropertyDeclaration, manifestContent: string | un // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; - hasManifestDefinition = !!manifestContent; + + hasManifestDefinition = !!(componentManifest && + ts.isPropertyAssignment(componentManifest) && + componentManifest.initializer.getText() === "\"json\""); } return { diff --git a/test/fixtures/linter/rules/BestPractices/Positive_6/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_6/Component.js new file mode 100644 index 000000000..c3e6750a9 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_6/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.Component", { + metadata: { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 6c4d44cb5..588344656 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -269,3 +269,28 @@ Generated by [AVA](https://avajs.dev). warningCount: 0, }, ] + +## General: Positive_6/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_6/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Include a manifest section into the Component.js', + messageDetails: 'manifest.json will be loaded and used, but is not defined in Component\'s metadata section', + ruleId: 'ui5-linter-add-manifest', + severity: 1, + }, + ], + warningCount: 1, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 077f3c8934e2c17e9d78cb010fb1a62b631fd161..186a1e281f3df9415c193c8b05b1e50bc9d270ed 100644 GIT binary patch literal 1418 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 Date: Fri, 26 Apr 2024 15:08:37 +0300 Subject: [PATCH 44/90] fix: Linting test filenames --- test/lib/linter/_linterHelper.ts | 8 +++++++- .../rules/snapshots/BestPractices.ts.md | 6 +++--- .../rules/snapshots/BestPractices.ts.snap | Bin 1418 -> 1446 bytes 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 42ea7e4c0..fae3f1412 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -135,7 +135,13 @@ function testDefinition( }); assertExpectedLintResults(t, res, fixturesPath, filePaths); res.forEach((results) => { - results.filePath = testName; + const chunks = testName.split("/").slice(0, -1); + + if (chunks.length > 0) { + results.filePath = path.join(...chunks, path.basename(results.filePath)); + } else { + results.filePath = testName; + } }); t.snapshot(res); }); diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 588344656..6fd4ab49e 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -73,7 +73,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_5/Component.js', + filePath: 'Negative_5/ParentComponent.js', messages: [], warningCount: 0, }, @@ -96,7 +96,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_6/Component.js', + filePath: 'Negative_6/ParentComponent.js', messages: [], warningCount: 0, }, @@ -264,7 +264,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_5/Component.js', + filePath: 'Positive_5/ParentComponent.js', messages: [], warningCount: 0, }, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 186a1e281f3df9415c193c8b05b1e50bc9d270ed..78358ed40de02d0df65d2c1d115f9b867f9110c2 100644 GIT binary patch literal 1446 zcmV;X1zGw*RzVYc`+nc|&G&M?T6R_C7607}LOa?Oud*XT3Xi+{*t4R>wKFeH z74nBvy`iL#IydJ#zT^#mR%!qAdE4fipQQIpWDxvOmW*)#lK{3-dJ9~^dbQd zlL@l6&`3qi3y;^tjI1iqD7KQ(X6o{&RmT;_xt{Gj z80&*pxH!LSaoM`?eO?oOWWKLGdx zK$?JY0_F&KGltqMWj-a~3j%&5;BNvRGJvB7U>lLHRv)W)+Ze7@Jl2K#aqbDJZ?TPw z#%gV2X_wy)d6#2-tSemHFRR|)>TEySmLAZSS(#=^iDrhPnbHHHnbQABGsl(htmwNe zHGWrfhHn7;e)IZK0;X4*GrY9goFQ1sT`___aD}VW_aIAq=pFC9prEHrUy} z2>6G95d+w10EZ3Wa|8I<1V&P^t|b#$c)Ft8W?i=7To-AzLO8>_%*IGt%5|h@_e(|E zGHsYT_eV}BrP&LPSYTY*?1XA+N7fkk1d~d$ijq~Q*7StUv|_H}Hq+dz3GFlPFUrcS zr=)87?qXz`P3>t83(XzZZ$CCb&-;QM?CQy$QQQt@+&Qat!{3+BH=XI6&l|als^<&2 z!sPD!<9V$bP9Ef9n-}&@l?#)Fy?pOvaZh2-t{j`GH(XH{QnO%) zrjx5EPvmC884oF`16Sz@t{o+rBen3Vydsz*S+{L5SE-3DoHnFl_-> zEZ~L}>7HI2Zp%1>9kBx6(XDWwIUUy^>`=|!Ea%t>QCIUK)a!q;kE*^S?5d~gJ{t*OUCU+s`ahTu<`XB!5lv*Cc;^07)MZR^rb2GH=|EGYgx5*W=GDE)Z~;fbR+T zlYor|aLfQi^vojDCqTV3>}q}=+{49PT3t0izqEYr{=;I9M@%K5!SDS9hPgFzOctx zxv2wZ6I8lvQFWxSdul;Dd{!5l2Xg4FYOqqrx|GUod!mo8xkaY`0^6d7w1+ML0GQay A!~g&Q literal 1418 zcmV;51$FvCRzVW+Xy-yr=SqiGu=D>?4g z5F?BiKOc(-00000000B+T3v`6RTTctOeRU&ZMUUDVSTx@NL$=Zn%yL=r4KFJQdUJv z!Jmp)?q+VXvrg^}GdH^~s8ApD#UiMnBCWJOs1)B7>O&uDUwjk6XNx~if*=UKXlIhF z$#j$1-L`JDvoD*Oll%95=R4=jnOv&Qx~lS`|K??(9qo#j*hwLU$KAv12~p$PSrBIn z`Ds;eC@G}Q&HIiodBdMm+CO*6wz=kK=q(c&1b>tzV;sOFfSr`yLDn(P<4Z)HPotxw zpv@oxZ6P|+8I)NB@Ctwr0bB*}1As9CiqxJc{p9StsAw{lKW^W?9kdmc25lpHhJXji z1X(+1q@ost$7^CnRuyOzJIUzSHVe;F-n42;9o|YI@`ceV*W5i3^Q~;vam6XF=Q=lb z^+7A#oZq#%Y+d+1uL(ag9G^zW=VPsbTZmo{{!>WpH2^mN{0JaT zz&HUm0k6hTo2ASp0zM(&IsrcsFk%454d4YMGSuqh73Yj$@ru&zUU9)#uU9Oe@5^C6 z-*@Xi-}<~hYD*8WWmcz_a-xYezpHh^R{(C_`urdP zrPbC6&#t#l2)1%poS+X};qLUkDHO=~fPjw(1H54w?9ZqTcJ>zner*SmeeGa!#Q?rF zfss^fP{~9#o~|gjS(j}%H$|*g2xoYe*&4B>Tt|xbxKzZJX~WdHK6zRx&7O9|BID9# zr&Uusvc|Y4m{giol&m_nrYCHs6>}B0ndV+iXrFO^Nmk}OB~{aRmm6CIlZ{#Yfo-gDIlLzv9@>(^VO1^xsJX@YB z7mMY}BSpb&UN|&0TbL{y;)f=S2MY)H=h#fW;flJDngvrdom@qEA~zGRIIW}>Qcrt= zYez}uNG-f7uL$Ny*6mwNdCV8ObwXBkdCg~4<+0tZIZJu3g;KtS&h8MoE~C-`p1Xr- z^_*aJE}g3IgPE0#lI%5IF=KZw$C^%Q!VNbzA=N~%{)F2CC@K_REC|ohOKqNw0f8p2 zQIH}82b#N;Z2F*eCvheyTm}ak^8x`M6YzOluxZsmUr?t8`hz+(P_}FUM-1RO z16VMCw+-N^34CJ$R!rQp_;o{&au;?t`q`j)>Mer-xP3qVCkn{m*CGOo`=H(%JTXC6yPYL*%fS(E2Y5*q;;B545MW#=JdTpb-`F(H? zH+OM;-TVOS2zjPsMucQ zSEJf9J>3?z=(sMM6=CN}*kPll=?i Date: Fri, 26 Apr 2024 15:11:49 +0300 Subject: [PATCH 45/90] fix: Eslint --- test/lib/linter/_linterHelper.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index fae3f1412..796fd1944 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -136,11 +136,11 @@ function testDefinition( assertExpectedLintResults(t, res, fixturesPath, filePaths); res.forEach((results) => { const chunks = testName.split("/").slice(0, -1); - + if (chunks.length > 0) { results.filePath = path.join(...chunks, path.basename(results.filePath)); } else { - results.filePath = testName; + results.filePath = testName; } }); t.snapshot(res); From 29f8cb7a9c4187178de6e4bb5c0848cf7d5a9a7e Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 26 Apr 2024 15:29:35 +0300 Subject: [PATCH 46/90] fix: Paths for windows --- test/lib/linter/_linterHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 796fd1944..3de488eb5 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -138,7 +138,7 @@ function testDefinition( const chunks = testName.split("/").slice(0, -1); if (chunks.length > 0) { - results.filePath = path.join(...chunks, path.basename(results.filePath)); + results.filePath = path.posix.join(...chunks, path.basename(results.filePath)); } else { results.filePath = testName; } From 1c6ee18de70520bb42627f8bd2364afb98028e61 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 7 May 2024 16:07:14 +0300 Subject: [PATCH 47/90] feat: Handle ES6 interface implementation --- src/linter/ui5Types/BestPractices.ts | 32 ++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index e94218919..4910b5757 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -98,7 +98,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon // Checks the interfaces and manifest const curClassAnalysis = classDefinition.members.reduce((acc, member) => { - const checkResult = doChecks(member as ts.PropertyDeclaration, manifestContent); + const checkResult = doPropChecks(member as ts.PropertyDeclaration, manifestContent); return mergeResults(acc, checkResult); }, {...returnTypeTemplate}); @@ -119,6 +119,8 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon checker, uiComponentImportVar, }) ?? result; + } else if (ts.isInterfaceDeclaration(declaration)) { + result.hasAsyncInterface = doAsyncInterfaceChecks(parentClass) ?? result.hasAsyncInterface; } return result; @@ -132,7 +134,33 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon } } -function doChecks(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { +function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean | undefined { + while (!importDeclaration || importDeclaration.kind !== ts.SyntaxKind.SourceFile) { + importDeclaration = importDeclaration.parent; + } + + // @ts-expect-error imports is part of SourceFileObject + const moduleImports = importDeclaration?.imports as ts.Node[]; + const coreLib = moduleImports?.find((importModule) => { + return importModule.getText() === "\"sap/ui/core/library\""; + }) as ts.StringLiteral | undefined; + + let hasAsyncInterface; + if (coreLib && ts.isImportDeclaration(coreLib.parent)) { + if (coreLib.parent.importClause?.namedBindings && + coreLib.parent.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { + hasAsyncInterface = coreLib.parent.importClause.namedBindings.elements.some( + (namedImport) => namedImport.getText() === "IAsyncContentCreation"); + } else { + hasAsyncInterface = + coreLib.parent.importClause?.name?.getText() === "IAsyncContentCreation"; + } + } + + return hasAsyncInterface; +} + +function doPropChecks(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { let classInterfaces: ts.ObjectLiteralElementLike | undefined; let componentManifest: ts.ObjectLiteralElementLike | undefined; From 4d9e33a267b5267e22b570603ddabc960b7f29a4 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 7 May 2024 16:13:21 +0300 Subject: [PATCH 48/90] test: Checks for inheritance in ES6 components --- .../BestPractices/Negative_7/Component.js | 9 ++++ .../BestPractices/Negative_7/manifest.json | 45 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.md | 15 ++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 1446 -> 1454 bytes 4 files changed, 69 insertions(+) create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_7/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_7/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_7/Component.js new file mode 100644 index 000000000..110f10e4a --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_7/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/fe/core/AppComponent"], function (AppComponent) { + "use strict"; + + return AppComponent.extend("mycomp.Component", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 6fd4ab49e..4c2b06296 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -110,6 +110,21 @@ Generated by [AVA](https://avajs.dev). }, ] +## General: Negative_7/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_7/Component.js', + messages: [], + warningCount: 0, + }, + ] + ## General: Positive_1/Component.js > Snapshot 1 diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 78358ed40de02d0df65d2c1d115f9b867f9110c2..60f46b8e72affbf8986d465f9357226dc1f06b56 100644 GIT binary patch delta 1443 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 From e2238e970b64717d3a8b1d2c0a2da6920ce3fb87 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 8 May 2024 09:25:13 +0300 Subject: [PATCH 49/90] refactor: Renames & docs --- src/linter/ui5Types/BestPractices.ts | 92 +++++++++++++++------------- 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 4910b5757..37bfcc81f 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -88,50 +88,52 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon checker: ts.TypeChecker; uiComponentImportVar: string; }): AsyncInterfaceFindType | undefined { - if (ts.isClassDeclaration(classDefinition)) { - const returnTypeTemplate = { - hasAsyncInterface: null, - routingAsyncFlag: null, - rootViewAsyncFlag: null, - hasManifestDefinition: false, - } as AsyncInterfaceFindType; - - // Checks the interfaces and manifest - const curClassAnalysis = classDefinition.members.reduce((acc, member) => { - const checkResult = doPropChecks(member as ts.PropertyDeclaration, manifestContent); - return mergeResults(acc, checkResult); - }, {...returnTypeTemplate}); - - const heritageAnalysis = - classDefinition?.heritageClauses?.flatMap((parentClasses: ts.HeritageClause) => { - return parentClasses.types.flatMap((parentClass) => { - const parentClassType = checker.getTypeAtLocation(parentClass); - - return parentClassType.symbol?.declarations?.flatMap((declaration) => { - let result = {...returnTypeTemplate} as AsyncInterfaceFindType; - // Continue down the heritage chain to search for - // the async interface or manifest flags - if (ts.isClassDeclaration(declaration) && - (!uiComponentImportVar || declaration?.name?.getText() !== uiComponentImportVar)) { - result = findAsyncInterface({ - classDefinition: declaration, - manifestContent, - checker, - uiComponentImportVar, - }) ?? result; - } else if (ts.isInterfaceDeclaration(declaration)) { - result.hasAsyncInterface = doAsyncInterfaceChecks(parentClass) ?? result.hasAsyncInterface; - } - - return result; - }); + if (!ts.isClassDeclaration(classDefinition)) { + return; + } + + const returnTypeTemplate = { + hasAsyncInterface: null, + routingAsyncFlag: null, + rootViewAsyncFlag: null, + hasManifestDefinition: false, + } as AsyncInterfaceFindType; + + // Checks the interfaces and manifest + const curClassAnalysis = classDefinition.members.reduce((acc, member) => { + const checkResult = doPropsCheck(member as ts.PropertyDeclaration, manifestContent); + return mergeResults(acc, checkResult); + }, { ...returnTypeTemplate }); + + const heritageAnalysis = + classDefinition?.heritageClauses?.flatMap((parentClasses: ts.HeritageClause) => { + return parentClasses.types.flatMap((parentClass) => { + const parentClassType = checker.getTypeAtLocation(parentClass); + + return parentClassType.symbol?.declarations?.flatMap((declaration) => { + let result = { ...returnTypeTemplate } as AsyncInterfaceFindType; + // Continue down the heritage chain to search for + // the async interface or manifest flags + if (ts.isClassDeclaration(declaration) && + (!uiComponentImportVar || declaration?.name?.getText() !== uiComponentImportVar)) { + result = findAsyncInterface({ + classDefinition: declaration, + manifestContent, + checker, + uiComponentImportVar, + }) ?? result; + } else if (ts.isInterfaceDeclaration(declaration)) { + result.hasAsyncInterface = doAsyncInterfaceChecks(parentClass) ?? result.hasAsyncInterface; + } + + return result; }); - }) ?? []; + }); + }) ?? []; - return [...heritageAnalysis, curClassAnalysis].reduce((acc, curAnalysis) => { - return mergeResults(acc ?? {...returnTypeTemplate}, curAnalysis ?? {...returnTypeTemplate}); - }); - } + return [...heritageAnalysis, curClassAnalysis].reduce((acc, curAnalysis) => { + return mergeResults(acc ?? { ...returnTypeTemplate }, curAnalysis ?? { ...returnTypeTemplate }); + }); } function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean | undefined { @@ -160,7 +162,7 @@ function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean | undefined return hasAsyncInterface; } -function doPropChecks(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { +function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { let classInterfaces: ts.ObjectLiteralElementLike | undefined; let componentManifest: ts.ObjectLiteralElementLike | undefined; @@ -301,6 +303,10 @@ function reportResults( } if (!hasAsyncInterface) { + // undefined has ambiguous meaning in that context. + // It could mean either implicit "true" or "false". + // To distinguish whether it's been set from manifest's config + // or not set at all, we'll use null. if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || routingAsyncFlag === false || routingAsyncFlag === undefined || (hasAsyncInterface === null && rootViewAsyncFlag === null && routingAsyncFlag === null)) { From 013122f722464d2d6f24f3c524a96f3c642c23a9 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 8 May 2024 09:29:39 +0300 Subject: [PATCH 50/90] fix: Eslint issues --- src/linter/ui5Types/BestPractices.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 37bfcc81f..11fcdc23e 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -103,7 +103,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon const curClassAnalysis = classDefinition.members.reduce((acc, member) => { const checkResult = doPropsCheck(member as ts.PropertyDeclaration, manifestContent); return mergeResults(acc, checkResult); - }, { ...returnTypeTemplate }); + }, {...returnTypeTemplate}); const heritageAnalysis = classDefinition?.heritageClauses?.flatMap((parentClasses: ts.HeritageClause) => { @@ -111,7 +111,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon const parentClassType = checker.getTypeAtLocation(parentClass); return parentClassType.symbol?.declarations?.flatMap((declaration) => { - let result = { ...returnTypeTemplate } as AsyncInterfaceFindType; + let result = {...returnTypeTemplate} as AsyncInterfaceFindType; // Continue down the heritage chain to search for // the async interface or manifest flags if (ts.isClassDeclaration(declaration) && @@ -132,7 +132,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon }) ?? []; return [...heritageAnalysis, curClassAnalysis].reduce((acc, curAnalysis) => { - return mergeResults(acc ?? { ...returnTypeTemplate }, curAnalysis ?? { ...returnTypeTemplate }); + return mergeResults(acc ?? {...returnTypeTemplate}, curAnalysis ?? {...returnTypeTemplate}); }); } From af1d2f9d21cb8a083405848b3a5f6bf27f0866b4 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 11:16:12 +0300 Subject: [PATCH 51/90] fix: Handle quoted properties --- src/linter/ui5Types/BestPractices.ts | 5 ++--- .../linter/rules/BestPractices/Negative_1/Component.js | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 11fcdc23e..8b7b7a854 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -169,10 +169,9 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string if (metadata && ts.isPropertyDeclaration(metadata) && metadata.initializer && ts.isObjectLiteralExpression(metadata.initializer)) { metadata.initializer.properties.forEach((prop) => { - if (prop.name?.getText() === "interfaces") { + if (["interfaces", "\"interfaces\""].includes(prop.name?.getText() ?? "")) { classInterfaces = prop; - } - if (prop.name?.getText() === "manifest") { + } else if (["manifest", "\"manifest\""].includes(prop.name?.getText() ?? "")) { componentManifest = prop; } }); diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js index 9c77822b8..fc14feb52 100644 --- a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js +++ b/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js @@ -3,8 +3,8 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { return UIComponent.extend("mycomp.Component", { metadata: { - interfaces: ["sap.ui.core.IAsyncContentCreation"], - manifest: "json", + "interfaces": ["sap.ui.core.IAsyncContentCreation"], + "manifest": "json", }, }); }); From 29fa1dbbcf4cb0f9ea0c837cb39a794c69560338 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 13:43:54 +0300 Subject: [PATCH 52/90] test: Add case for missing view & routing --- .../rules/BestPractices/Positive_7/Component.js | 9 +++++++++ .../rules/BestPractices/Positive_7/manifest.json | 14 ++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_7/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js new file mode 100644 index 000000000..f513569e3 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.Component", { + "metadata": { + "manifest": "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json new file mode 100644 index 000000000..24562d886 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json @@ -0,0 +1,14 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + } +} From a7a307e6ddc459657676945b71324771de4292b7 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 14:43:49 +0300 Subject: [PATCH 53/90] refactor: Migrate checks to enum --- src/linter/ui5Types/BestPractices.ts | 118 +++++++++++------- .../rules/snapshots/BestPractices.ts.md | 25 ++++ .../rules/snapshots/BestPractices.ts.snap | Bin 1454 -> 1478 bytes 3 files changed, 96 insertions(+), 47 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 8b7b7a854..1abe8f9bb 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -9,11 +9,13 @@ type propsRecord = Record; +enum AsyncInterfaceStatus {true, false, propNotSet, parentPropNotSet}; + interface AsyncInterfaceFindType { - hasAsyncInterface: boolean | undefined | null; + hasAsyncInterface: AsyncInterfaceStatus; hasManifestDefinition: boolean; - routingAsyncFlag: boolean | undefined | null; - rootViewAsyncFlag: boolean | undefined | null; + routingAsyncFlag: AsyncInterfaceStatus; + rootViewAsyncFlag: AsyncInterfaceStatus; } export default function analyzeComponentJson( @@ -60,18 +62,17 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy // undefined = async flag is missing // true|false = async flag is explicitly set - const compareValues = (aProp: null | undefined | boolean, - bProp: null | undefined | boolean): null | undefined | boolean => { - let result = null; - if (aProp === undefined || bProp === undefined) { - result = undefined; - } - if (typeof aProp === "boolean" || typeof bProp === "boolean") { - // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing - result = aProp || bProp; - } - - return result; + const compareValues = (aProp: AsyncInterfaceStatus, bProp: AsyncInterfaceStatus): AsyncInterfaceStatus => { + const priorityCheck = [ + AsyncInterfaceStatus.parentPropNotSet, + AsyncInterfaceStatus.propNotSet, + AsyncInterfaceStatus.false, + AsyncInterfaceStatus.true, + ]; + const aIndex = priorityCheck.indexOf(aProp); + const bIndex = priorityCheck.indexOf(bProp); + + return (aIndex > bIndex) ? aProp : bProp; }; return { @@ -93,9 +94,9 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon } const returnTypeTemplate = { - hasAsyncInterface: null, - routingAsyncFlag: null, - rootViewAsyncFlag: null, + hasAsyncInterface: AsyncInterfaceStatus.propNotSet, + routingAsyncFlag: AsyncInterfaceStatus.propNotSet, + rootViewAsyncFlag: AsyncInterfaceStatus.propNotSet, hasManifestDefinition: false, } as AsyncInterfaceFindType; @@ -136,7 +137,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon }); } -function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean | undefined { +function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatus { while (!importDeclaration || importDeclaration.kind !== ts.SyntaxKind.SourceFile) { importDeclaration = importDeclaration.parent; } @@ -147,15 +148,19 @@ function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean | undefined return importModule.getText() === "\"sap/ui/core/library\""; }) as ts.StringLiteral | undefined; - let hasAsyncInterface; + let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; if (coreLib && ts.isImportDeclaration(coreLib.parent)) { if (coreLib.parent.importClause?.namedBindings && coreLib.parent.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { - hasAsyncInterface = coreLib.parent.importClause.namedBindings.elements.some( + const hasAsyncImport = coreLib.parent.importClause.namedBindings.elements.some( (namedImport) => namedImport.getText() === "IAsyncContentCreation"); + + hasAsyncInterface = hasAsyncImport ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } else { - hasAsyncInterface = + const implementsAsyncInterface = coreLib.parent.importClause?.name?.getText() === "IAsyncContentCreation"; + + hasAsyncInterface = implementsAsyncInterface ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } } @@ -177,20 +182,22 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string }); } - let hasAsyncInterface = null; + let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { - hasAsyncInterface = classInterfaces.initializer + const hasAsyncInterfaceProp = classInterfaces.initializer .elements.some((implementedInterface) => implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); + + hasAsyncInterface = hasAsyncInterfaceProp ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } // undefined has ambiguous meaning in that context. // It could mean either implicit "true" or "false". // To distinguish whether it's been set from manifest's config // or not set at all, we'll use null. - let rootViewAsyncFlag: boolean | undefined | null = null; - let routingAsyncFlag: boolean | undefined | null = null; + let rootViewAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; + let routingAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; let hasManifestDefinition = false; if (componentManifest && @@ -210,25 +217,47 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string } if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.rootView?.value) && - typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { - rootViewAsyncFlag = manifestSapui5Section?.rootView?.value.async?.value; + instanceOfPropsRecord(manifestSapui5Section?.rootView?.value)) { + rootViewAsyncFlag = AsyncInterfaceStatus.propNotSet; + + if (typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { + const isRootViewAsync = manifestSapui5Section?.rootView?.value.async?.value; + rootViewAsyncFlag = isRootViewAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + } } if (instanceOfPropsRecord(manifestSapui5Section) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value) && - instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && - typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { - routingAsyncFlag = manifestSapui5Section?.routing?.value.config?.value.async?.value; + instanceOfPropsRecord(manifestSapui5Section?.routing?.value)) { + routingAsyncFlag = AsyncInterfaceStatus.propNotSet; + + if (instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && + typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { + const isRoutingAsync = manifestSapui5Section?.routing?.value.config?.value.async?.value; + routingAsyncFlag = isRoutingAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + } } } else { const parsedManifestContent = JSON.parse(manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; - // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef - rootViewAsyncFlag = rootView ? rootView.async as boolean | undefined : rootViewAsyncFlag; - routingAsyncFlag = routing?.config ? routing.config.async : routingAsyncFlag; + + if (rootView) { + rootViewAsyncFlag = AsyncInterfaceStatus.propNotSet; + // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef + const isRootViewAsync = rootView.async as boolean | undefined; + if (typeof isRootViewAsync === "boolean") { + rootViewAsyncFlag = isRootViewAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + } + } + + if (routing) { + routingAsyncFlag = AsyncInterfaceStatus.propNotSet; + const isRoutingAsync = routing?.config?.async; + if (typeof isRoutingAsync === "boolean") { + routingAsyncFlag = isRoutingAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + } + } hasManifestDefinition = !!(componentManifest && ts.isPropertyAssignment(componentManifest) && @@ -294,21 +323,16 @@ function reportResults( reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-add-manifest", // TODO: Add rule id + ruleId: "ui5-linter-add-manifest", message: "Include a manifest section into the Component.js", messageDetails: "manifest.json will be loaded and used, " + "but is not defined in Component's metadata section", }); } - if (!hasAsyncInterface) { - // undefined has ambiguous meaning in that context. - // It could mean either implicit "true" or "false". - // To distinguish whether it's been set from manifest's config - // or not set at all, we'll use null. - if (rootViewAsyncFlag === false || rootViewAsyncFlag === undefined || - routingAsyncFlag === false || routingAsyncFlag === undefined || - (hasAsyncInterface === null && rootViewAsyncFlag === null && routingAsyncFlag === null)) { + if (hasAsyncInterface !== AsyncInterfaceStatus.true) { + if ([AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(rootViewAsyncFlag) || + [AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(routingAsyncFlag)) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, @@ -320,7 +344,7 @@ function reportResults( }); } } else { - if (rootViewAsyncFlag === true) { + if (rootViewAsyncFlag === AsyncInterfaceStatus.true) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Warning, @@ -330,7 +354,7 @@ function reportResults( messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } - if (routingAsyncFlag === true) { + if (routingAsyncFlag === AsyncInterfaceStatus.true) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Warning, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 4c2b06296..270ec3515 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -309,3 +309,28 @@ Generated by [AVA](https://avajs.dev). warningCount: 1, }, ] + +## General: Positive_7/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Positive_7/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View and Routing are not configured to load targets asynchronously', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 60f46b8e72affbf8986d465f9357226dc1f06b56..1debf188df974f8275741887c9123069097f25e8 100644 GIT binary patch delta 1471 zcmV;w1wi_)3&sn7K~_N^Q*L2!b7*gLAa*kf0|4;{YD_dk$}bvtOiKv+%u_AF-!yt< zSquYtvZDGToyQ-G2mk;800003?OIK28$}fU-mcen+my5v6sZVlRD{}!#I6&^DOC@x zT2!S)P*vimT&jt8>}*)iSi9qd96%~Uz@;EjE(jIWABiG=#DN5LM0afmdmDR`^v6-Vxx~A(^Y?x8z4!LLJztq|Rryu_y$eD++7+*{BSH#~yZhL4 zqRO>1FHRNmhg7Yuq>wr{=R3aSb$?cA|MYp==9-_R_f2FF{85&SQ2^rrwo!U3SqD9j zFA}wX4G#~0gEoQ)w25ecyHjQX!0P}$2Jj7l-vMkVph&HO($CM#iLxeR>F1U$TR@vZ zY0yJNFA?wvnILN`4VBfr@OV{B%ZdUGV;dRmwvEE`ly^uqqz-ST5P4v@!ZmlFiFqnp zaa?hn>)G~=ksfG;i}O1cm#qok=T+fHMjTq;o^)h?wR_TR7mQ{XjNNUijSk;_(jL zk8@9dNPWxMxM-~PY%J~ay8-WVq{rzB7x(L$_qVpQA8kwbY0IokGo?f`1JO+BfzV9p zzSPWA5;Lsg3{0)ZnBlncofW-fr$+B6m)`>Tf0t|LXOUn|` zh9_*M6>}B0ndV+qXrFO^QI=;tB~`k9k@MDaP26`9I1s@;bp-b$vV## zQy%k$Ztjp(Twe8AMR{yTbIi%S*F-6Q-$Z9eh+Idb(gB`3f?@TnU^OnCitvMxm5h?? zHC!=mw=cIhoXIgaT-caYW5N7mZWExWP<$~jJV!6KcsBYNnz#f|di&s=#+nVyopKsI z(7GKv6NIAu4UKt@fQzlrvahjeMzvp4JF2}-?Wi_eGJyRC@QMM<8^8w!aKHqAel`Is z#_nV(`(z4uDg{iZ0C5wj(Yxj39UJUXV7qpA3Q%NPCa}o_ z9yR;9;qF1QecCoGf2f(+KGdhoCHMV_30yLP?@i!06S!dlms3E|0%}qJd#n3@K6CSt zvlj4`1zfd&YZh=W4eZVUGnvGFC+<6O---KP#(l?qK4Q)#Z-pa0(7LU+Lb`Y9rw;>% zX#z*hb(((KGcC(*!xoG$>5}=P+|JLaP_f;}uSB&cyK*jU!Es$SBf|WZu)}ms!x#1_ zn`!94*aVp_TT~n=?5O@qLmd{tt5nBEh^g004C##gPC2 delta 1447 zcmV;Y1z7sV3$6=)K~_N^Q*L2!b7*gLAa*kf0|53yZ@``noDG9gv@i;1Ql<|SWR5BV z;Q5OZPg?4q!m1yO2mk;800003?OIK28$}fU-mcen+q7vZC{hv9s0g(ciCrg-Q>q?X zwWvyqpsK`Axm08C*x9h2v3AD^Ie=7zfJ=o$xgb*Br*^5Fu+7+*}qe2RgyZhPm zqQwr{>pQ;W4Sz;y|I7v3=9-_P_f2FF{85&SQ2^rrwo`f=S%*B2 zFA%k_hKGlLK^s8?+C+4q-6=B<;0*vD1Na8OZvb`>P^8vC=@-hgqN2%Iy4<>TD`+z) z4cbEVG69d039`1)P({rNkJrSstSZnjwv*9r+bBFwd52X~>hMttkr#%mTyyu?n76W3 z#}y~Io@qZA>48?bIKN|Y*}Cw3UK4&~#G!faNk`Uyx+l$c!Dx2D*xi=uXzRn}c*5l> zxEx>CTuvlhu7b;nboEkS1W1fLQ|Gj-fV7na>FLl7Jrx_?v)74B(gn*hZwQ)#FsWYYg^OJkf#s z3GNAhsqZ)&myETZjip_FH{e~4^f+DN;(l54{?>N(qiyLvZJCv6rj%%AAet#X6q+gh zFEulj#0;xA15@iUW;mgIXGP!GsnL7N<+lKSzkU5U0h24`@|Cr687$?Vkl6#SaCQ3r zkV(cz1bj;9qwFQHKc^Ph*}n+*hkzji*lhrRM-1Q#1NhklhElO^A`@A7x}w}>UAExd z5NWkSIK#Wl=15!0b);zZOGVl;EtuN(M^7rH*-MU?XI$Fsq-ttM))@B$lS;FSl2xbH z^n}f{Vy@yg)7+~G?KAE#$jXeTq-y%^LS&jPt!a)3%^lZoJvKlu`hp$m=*gZ_+zw`c z+&!ap!{49JH=W6x&l|als^<&2!ua0&lXpWXb zdCV7jafhtx@|w@8%40hh$DGW2izwxP7tz@nBG=KVbb#m1U|2mPSe;9!D*Rw%C8H#J zO;=3Y?b{tqXL8I97d9rTkz@=7b+1J=CMzvp4JF2}&?Wi_eGJpdH@TvjK8NdeyaL@#Qelh_o z#_nV(`&0^eIt5Ip0C5|rGbv!w0mqU76{Dd$_pEYpcuzSTAkx`k)JJ9UJUXV7qaD3Q%NPCa}o_ z9y9y7;qF1QecCoGf2f(+KGdhpCHMV_30yXTYbNlk3EVP)D=DC80rjZ=z0-YvpS}Ic zIScs80ufmZYXx-IUAw9VC(}#h> zG=XF0I!!@Z!^^o2dj z%1s>@n;_F=i>f1q-IWX4<+HjT&^(YsdsY3FI?|z3Zrfu$Y|R}q{TJ{JIhj*1003;+ B$$J0* From 79cdbe79bb49518d42a412723653ff2333ca3e21 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 14:53:52 +0300 Subject: [PATCH 54/90] fix: Reset result template --- src/linter/ui5Types/BestPractices.ts | 6 +-- .../{Positive_7 => Negative_8}/Component.js | 0 .../{Positive_7 => Negative_8}/manifest.json | 0 .../rules/snapshots/BestPractices.ts.md | 40 +++++++----------- .../rules/snapshots/BestPractices.ts.snap | Bin 1478 -> 1466 bytes 5 files changed, 18 insertions(+), 28 deletions(-) rename test/fixtures/linter/rules/BestPractices/{Positive_7 => Negative_8}/Component.js (100%) rename test/fixtures/linter/rules/BestPractices/{Positive_7 => Negative_8}/manifest.json (100%) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 1abe8f9bb..013d742af 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -94,9 +94,9 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon } const returnTypeTemplate = { - hasAsyncInterface: AsyncInterfaceStatus.propNotSet, - routingAsyncFlag: AsyncInterfaceStatus.propNotSet, - rootViewAsyncFlag: AsyncInterfaceStatus.propNotSet, + hasAsyncInterface: AsyncInterfaceStatus.parentPropNotSet, + routingAsyncFlag: AsyncInterfaceStatus.parentPropNotSet, + rootViewAsyncFlag: AsyncInterfaceStatus.parentPropNotSet, hasManifestDefinition: false, } as AsyncInterfaceFindType; diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js b/test/fixtures/linter/rules/BestPractices/Negative_8/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_7/Component.js rename to test/fixtures/linter/rules/BestPractices/Negative_8/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json b/test/fixtures/linter/rules/BestPractices/Negative_8/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json rename to test/fixtures/linter/rules/BestPractices/Negative_8/manifest.json diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 270ec3515..5904e0261 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -125,6 +125,21 @@ Generated by [AVA](https://avajs.dev). }, ] +## General: Negative_8/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Negative_8/Component.js', + messages: [], + warningCount: 0, + }, + ] + ## General: Positive_1/Component.js > Snapshot 1 @@ -309,28 +324,3 @@ Generated by [AVA](https://avajs.dev). warningCount: 1, }, ] - -## General: Positive_7/Component.js - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'Positive_7/Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Root View and Routing are not configured to load targets asynchronously', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', - ruleId: 'ui5-linter-no-sync-loading', - severity: 2, - }, - ], - warningCount: 0, - }, - ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 1debf188df974f8275741887c9123069097f25e8..07468e0525f9e5c0558e80cc876f46f4c1200196 100644 GIT binary patch literal 1466 zcmV;r1x5NnRzVq{{ps2__600000000B+T1{*lMHK$tuGeDyZRAcYh*|6TRcE<@hfK-HlOF^Ps5GtrY5=DpuHx3|F4sd{;I3jTXA*h77R_clF z+79+6_9p3%ExNg6ci+y>e&2lWy_x5W<)ST1uXyiX63SAxc$FO!j&QksfITZJTv?0a zOfGvwR%_A`j>;@}mgn%AH!qcU_M&NW#ZS|FI#TfeC{5ZJfJp$mDY=V`!>-GhiCR~~ z!^5DhAOdY8I@oHIS_1GIfR6xt4d6EbdkDx=v!mp5#RXAPq^(@;+_@999h3y^AbOF2 zhe-z+yJ)B+7lq3!V$LZ`&@gtB*0OCCt}ERmvhJwhQ39bChRa-W`{{_c(q+pQC%Kw$ zJs9bNRxmlQZF1?V@H}1-UZ}^RCGI+wQ|TNu-2tQC0b{2v(Przx zE;qpC)If8YkGb3cm-&I_ayo)b?PeR7`UHRifJ0GyY5|`o8V$D*z2*O>fZA&SegN4YFD`a+oE0~?S zH)N9bApxHddU)v-us@?F*y+Cr_=kWY4cM;%M>XJc4ft6Hh7yq>KNXsIvLx+#)oH@H zC1f=MID@;?_K+=MTaIY9ON4BxCQPmSW2dB4>;+3KG47b`l&mYusW9#e=19d#(kWY& zx+_ekB(o(qnc{9mD35V(*(uGt(vfw~UJebjqdCk`p}1vx&Bq$(c~7vzZ7ta|lAHdB z`{$Lac?YuDx;35gcr8j7Dm9mAILa{Ja$ma{Cr}BcEJU2U4%uVKI z`RrtVCO0#hVRO}*Evmv%%1-N1l&`3@L%B(<9ZI^O0S7hUWer%=fcG`vkPiH$14e}3 zNmKfX1n^`6m`ecSHc)31z_bBeGk{x0sCjZQ+?I9@`yvItuU+9Dvs$h}n1PzxSIDd`v*EoND07>r=R-)?f zsW}1NhPat{cD&1Gta`MpHmB6^HLQe8=HC4&Q5p@2H;w z=?n3$aHI=bceE>{`*-~Gfgdn+;J7}Z$4?V;PRXvDg7FnyGEbCR=QA=;Y$x*TQSIrD zGZ(gG*)}VR;QUIM!EsI96XqBz)|KyU{F5$Ilr2Y?9cMxNJXRHo`*LW_s<%={+LX#o UbG(bMStZkd0r$A%EFUre06{R^IRF3v literal 1478 zcmV;%1v&abRzV-8wU_72RJ}a9FaJH5L7~3EA>Qo zZ3lZBdz19XQMM5RsX#ULOa?OudyRS3Xi+{*mI)FwKFeH z74nBvt*)eyIydJ#zT|a(R%!qAdE4fipQQIqWDxvOmW)vV;{di%dMjB6J&!LEwSNr{ z4}&&>2(*c4f4fs=0l@13J_hg&fZqXZC!k2Jfzr><%!#rlW9jFXEn7gFL21xKL@yEW z2$>*jD-D&^yzqEcOv{P_4PzS_?Y51=^OSc;HKY!2r4V^wxWYAepNV-YTX9@*oa@>4 zjgcN`g^Tk$7MHCF-{)1~M@Af4;GT43wR_TR7mQ{XjNNUijSk;_(jLk8@8*eaqRn zXsq>YEba2U0q=68$LR_e_v@PXx3;q%ZA8Gpyna zOs&V5;kfdh6}@ApM(-$>-vapK=I_S{m|Q8BFRzu$U@3Qm%pP!stJ8OfOfo(q;8Q{$ zWiNsKIkmvf{!PHY1PmF#E(17h0ACouFD5XQiggp2$imZQ@W(>&Cg=CIJ*asAe91N4F~*ujpT>{-R_V8&guTG#!3`Fz8f z%=x^YE2~<*kSmPu$v=_Ts_vBYrK!?PX`)mtmdZ~T1-E%&@5D@Dys($=9WPE5rgrDp zbgk}+nvj|WLo}RRS$QHi9nN@2NgcR7PjKxh$sDPLSK(#B9LYM*7E>Pcg>LSURa{>6 zSw(qlM{~@{yw^l2-$Z9eh+Idb(gB`3f?@TnU^OnCitvMxm5h??HC!=mw=cIhoXIga zT-caYW5N7mZWExWP<$~jJV!6KcsBYNnz#f|di&s=#+nVyopKsI(7GKv6NIAu4UKt@ zfQzlrvahjeMzvp4JF2}-?Wi_eGJyRC@QMM<8^8w!aKHq9HUTTf?qn(ZWD0mH1x%*^ zaTBQ1DPYn9u2{egE7Co^KFpSJ20LQ~zOz%|K6BcpLD-?1J6X=L6QZW(MX1;RWgk_2 zTi6v()w-m;BI`#Y-X`_6g1qkJV~5y%w=4_|knXbsp}X72KbWNVaVv4T=p=sa@+-?E zqm%eGiC>fWH8y^YE0iShYp0!Arcjc^uSxux#IH&G`T&yN$F0QGY%_1(i~5sIz#H-P zrwasJCg2AG{vu$r0UR>`5v@OEdN`%X#z*hb(((KGcC(*!xoG$>5}=P+|JLaP_f;}uSB&cyK*jU!Es$SBf|WZ zu)}ms!x#1_n`!94*aVp_TT~n=?5 Date: Wed, 15 May 2024 14:54:36 +0300 Subject: [PATCH 55/90] refactor: Remove redundant comments --- src/linter/ui5Types/BestPractices.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 013d742af..6cdfca7f1 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -58,10 +58,6 @@ export default function analyzeComponentJson( } function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): AsyncInterfaceFindType { - // null = parent property does not exist i.e. rootView - // undefined = async flag is missing - // true|false = async flag is explicitly set - const compareValues = (aProp: AsyncInterfaceStatus, bProp: AsyncInterfaceStatus): AsyncInterfaceStatus => { const priorityCheck = [ AsyncInterfaceStatus.parentPropNotSet, From bd2f0da6152577758f7ce5dbb4dbc665f55e4898 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 15:22:47 +0300 Subject: [PATCH 56/90] refactor: Rename BestPractices --- src/linter/ui5Types/BestPractices.ts | 2 +- src/linter/ui5Types/SourceFileLinter.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 6cdfca7f1..511b532c9 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -1,6 +1,6 @@ import ts from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; -import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.d.ts"; +import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.js"; import {LintMessageSeverity} from "../LinterContext.js"; type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index a59c8972b..aa3fec960 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -1,7 +1,7 @@ import ts, {Identifier} from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; import LinterContext, {ResourcePath, CoverageCategory, LintMessageSeverity} from "../LinterContext.js"; -import analyzeComponentJson from "./BestPractices.js"; +import analyzeComponentJson from "./bestPractices.js"; interface DeprecationInfo { symbol: ts.Symbol; From 96792208925fc0d13ce86176e1616c6b55fb5c28 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 15:28:34 +0300 Subject: [PATCH 57/90] refactor: Exit early --- src/linter/ui5Types/BestPractices.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 511b532c9..c261fdc7a 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -33,7 +33,10 @@ export default function analyzeComponentJson( parent = parent.parent; } - if (!ts.isSourceFile(parent) || !parent.fileName.endsWith("/Component.js") || !classDesc) { + if (!ts.isSourceFile(parent) || + !parent.fileName.endsWith("/Component.js") || + !classDesc || + !ts.isClassDeclaration(classDesc)) { return; } @@ -47,13 +50,12 @@ export default function analyzeComponentJson( return varName; }, ""); - if (classDesc && ts.isClassDeclaration(classDesc)) { - const analysisResult = findAsyncInterface({ - classDefinition: classDesc, manifestContent, checker, uiComponentImportVar}); + const analysisResult = findAsyncInterface({ + classDefinition: classDesc, manifestContent, checker, uiComponentImportVar, + }); - if (analysisResult) { - reportResults(analysisResult, reporter, classDesc); - } + if (analysisResult) { + reportResults(analysisResult, reporter, classDesc); } } From 0cd5a7f6af1b559965a53a665a2754ad26164c3b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 15:29:47 +0300 Subject: [PATCH 58/90] refactor: Remove redundant checks --- src/linter/ui5Types/BestPractices.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index c261fdc7a..94af44ad8 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -87,10 +87,6 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon checker: ts.TypeChecker; uiComponentImportVar: string; }): AsyncInterfaceFindType | undefined { - if (!ts.isClassDeclaration(classDefinition)) { - return; - } - const returnTypeTemplate = { hasAsyncInterface: AsyncInterfaceStatus.parentPropNotSet, routingAsyncFlag: AsyncInterfaceStatus.parentPropNotSet, From a8e62d259d8692e4a34af6e911095186026f4bbd Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 15:33:37 +0300 Subject: [PATCH 59/90] refactor: Resolve SourceFile --- src/linter/ui5Types/BestPractices.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 94af44ad8..428a77969 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -26,7 +26,7 @@ export default function analyzeComponentJson( ) { let parent = node.parent; let classDesc; - while (!parent || parent.kind !== ts.SyntaxKind.SourceFile) { + while (parent && parent.kind !== ts.SyntaxKind.SourceFile) { if (parent.kind === ts.SyntaxKind.ClassDeclaration) { classDesc = parent; } @@ -132,7 +132,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon } function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatus { - while (!importDeclaration || importDeclaration.kind !== ts.SyntaxKind.SourceFile) { + while (importDeclaration && importDeclaration.kind !== ts.SyntaxKind.SourceFile) { importDeclaration = importDeclaration.parent; } From da987fd1394d5f7c0a2dc579318867fa1f786561 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 15:39:54 +0300 Subject: [PATCH 60/90] refactor: Cleanup redundant code --- src/linter/ui5Types/BestPractices.ts | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 428a77969..0c62df86e 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -40,18 +40,8 @@ export default function analyzeComponentJson( return; } - // @ts-expect-error imports is part of SourceFileObject - const moduleImports = parent.imports as ts.Node[]; - const uiComponentImportVar = moduleImports.reduce((varName: string, importClause: ts.Node) => { - if (ts.isIdentifier(importClause) && importClause.text === "sap/ui/core/UIComponent" && - ts.isImportDeclaration(importClause.parent)) { - varName = importClause.parent?.importClause?.name?.getText() ?? ""; - } - return varName; - }, ""); - const analysisResult = findAsyncInterface({ - classDefinition: classDesc, manifestContent, checker, uiComponentImportVar, + classDefinition: classDesc, manifestContent, checker, }); if (analysisResult) { @@ -81,11 +71,10 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy }; } -function findAsyncInterface({classDefinition, manifestContent, checker, uiComponentImportVar}: { +function findAsyncInterface({classDefinition, manifestContent, checker}: { classDefinition: ts.ClassDeclaration; manifestContent: string | undefined; checker: ts.TypeChecker; - uiComponentImportVar: string; }): AsyncInterfaceFindType | undefined { const returnTypeTemplate = { hasAsyncInterface: AsyncInterfaceStatus.parentPropNotSet, @@ -109,13 +98,11 @@ function findAsyncInterface({classDefinition, manifestContent, checker, uiCompon let result = {...returnTypeTemplate} as AsyncInterfaceFindType; // Continue down the heritage chain to search for // the async interface or manifest flags - if (ts.isClassDeclaration(declaration) && - (!uiComponentImportVar || declaration?.name?.getText() !== uiComponentImportVar)) { + if (ts.isClassDeclaration(declaration)) { result = findAsyncInterface({ classDefinition: declaration, manifestContent, checker, - uiComponentImportVar, }) ?? result; } else if (ts.isInterfaceDeclaration(declaration)) { result.hasAsyncInterface = doAsyncInterfaceChecks(parentClass) ?? result.hasAsyncInterface; From cacf9007fbdae7bef2423685eae7c8feeae952e0 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 17:01:33 +0300 Subject: [PATCH 61/90] refactor: Improve messaging --- src/linter/ui5Types/BestPractices.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 0c62df86e..36fcd8be1 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -314,11 +314,20 @@ function reportResults( if (hasAsyncInterface !== AsyncInterfaceStatus.true) { if ([AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(rootViewAsyncFlag) || [AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(routingAsyncFlag)) { + let componentsToAddress = []; + if (AsyncInterfaceStatus.parentPropNotSet !== rootViewAsyncFlag) { + componentsToAddress.push("Root View"); + } + if (AsyncInterfaceStatus.parentPropNotSet !== routingAsyncFlag) { + componentsToAddress.push("Routing"); + } + reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", - message: "Root View and Routing are not configured to load targets asynchronously", + message: `${componentsToAddress.join(" and ")} ${componentsToAddress.length > 1 ? "are" : "is"} ` + + "not configured to load targets asynchronously", messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", From 4d8a01c94bbaaec87b2b82b401ab9ed2dc70505c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 17:06:06 +0300 Subject: [PATCH 62/90] fix: Eslint --- src/linter/ui5Types/BestPractices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/BestPractices.ts index 36fcd8be1..4fcd2e5e7 100644 --- a/src/linter/ui5Types/BestPractices.ts +++ b/src/linter/ui5Types/BestPractices.ts @@ -314,7 +314,7 @@ function reportResults( if (hasAsyncInterface !== AsyncInterfaceStatus.true) { if ([AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(rootViewAsyncFlag) || [AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(routingAsyncFlag)) { - let componentsToAddress = []; + const componentsToAddress = []; if (AsyncInterfaceStatus.parentPropNotSet !== rootViewAsyncFlag) { componentsToAddress.push("Root View"); } From c30a8c91bedd8b8aa2ec586cfbee5e4a064f8e66 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Wed, 15 May 2024 17:40:31 +0300 Subject: [PATCH 63/90] fix: Rename bestPractices.ts --- src/linter/ui5Types/{BestPractices.ts => bestPractices.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/linter/ui5Types/{BestPractices.ts => bestPractices.ts} (100%) diff --git a/src/linter/ui5Types/BestPractices.ts b/src/linter/ui5Types/bestPractices.ts similarity index 100% rename from src/linter/ui5Types/BestPractices.ts rename to src/linter/ui5Types/bestPractices.ts From adae2acddc7fdef5cadc1ae7a7c9cc5fd7e33021 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Thu, 16 May 2024 12:25:29 +0300 Subject: [PATCH 64/90] refactor: Extract virBasePath from filePaths --- src/linter/linter.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/linter/linter.ts b/src/linter/linter.ts index 13c51523c..5b0283459 100644 --- a/src/linter/linter.ts +++ b/src/linter/linter.ts @@ -87,16 +87,19 @@ export async function lintProject({ export async function lintFile({ rootDir, pathsToLint, namespace, reportCoverage, includeMessageDetails, }: LinterOptions): Promise { - const reader = createReader({ - fsBasePath: rootDir, - virBasePath: namespace ? `/resources/${namespace}/` : "/", - }); let resolvedFilePaths; + let virBasePath = ""; if (pathsToLint?.length) { const absoluteFilePaths = resolveFilePaths(rootDir, pathsToLint); resolvedFilePaths = transformFilePathsToVirtualPaths( absoluteFilePaths, rootDir, "/", rootDir); + + virBasePath = resolvedFilePaths[0].split("/").slice(0, -1).join("/"); } + const reader = createReader({ + fsBasePath: rootDir, + virBasePath: `${virBasePath}/`, + }); const res = await lint(reader, { rootDir, From b3c1bb53805268957f238249fbb97a74b74f25da Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 09:00:42 +0300 Subject: [PATCH 65/90] feat: Provide links to manifest.json when needed --- src/linter/ui5Types/SourceFileLinter.ts | 14 +++--- src/linter/ui5Types/bestPractices.ts | 59 ++++++++++++++++++------- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index aa3fec960..6f9d8deab 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -71,12 +71,14 @@ export default class SourceFileLinter { } else if (node.kind === ts.SyntaxKind.ImportDeclaration) { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { - analyzeComponentJson( - node as ts.ExpressionWithTypeArguments, - this.#manifestContent, - this.#reporter, - this.#checker - ); + analyzeComponentJson({ + node: node as ts.ExpressionWithTypeArguments, + manifestContent: this.#manifestContent, + resourcePath: this.#resourcePath, + reporter: this.#reporter, + context: this.#context, + checker: this.#checker, + }); } // Traverse the whole AST from top to bottom diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 4fcd2e5e7..6f90ea99d 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -1,7 +1,9 @@ import ts from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.js"; -import {LintMessageSeverity} from "../LinterContext.js"; +import LinterContext, {LintMessage, LintMessageSeverity} from "../LinterContext.js"; +import jsonMap from "json-source-map"; +import type {jsonSourceMapType} from "../manifestJson/ManifestLinter.js"; type propsRecordValueType = string | boolean | undefined | null | number | propsRecord; type propsRecord = Record(manifestContent ?? "{}"); + const report = (pointerKey: string, message: LintMessage) => { + if (manifestContent) { + // If the manifest.json is present, then we need to redirect the message pointers to it + const {key: posInfo} = pointers[pointerKey]; + context.addLintingMessage(resourcePath.replace("Component.js", "manifest.json"), {...message, ...posInfo}); + } else { + reporter.addMessage({...message, ...{node: classDesc}}); + } + }; + if (rootViewAsyncFlag === AsyncInterfaceStatus.true) { - reporter.addMessage({ - node: classDesc, + report("/sap.ui5/rootView/async", { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + @@ -345,8 +371,7 @@ function reportResults( }); } if (routingAsyncFlag === AsyncInterfaceStatus.true) { - reporter.addMessage({ - node: classDesc, + report("/sap.ui5/routing/config/async", { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + From 168fd141fd60eff6d81d0a3e0eee832c4ec169b6 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 09:07:12 +0300 Subject: [PATCH 66/90] fix: Link resolver for LinterContext --- src/linter/LinterContext.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/linter/LinterContext.ts b/src/linter/LinterContext.ts index dbdcdc68a..352952385 100644 --- a/src/linter/LinterContext.ts +++ b/src/linter/LinterContext.ts @@ -1,5 +1,6 @@ import {AbstractAdapter, AbstractReader} from "@ui5/fs"; import {createReader} from "@ui5/fs/resourceFactory"; +import {resolveLinks} from "../formatter/lib/resolveLinks.js"; export type FilePath = string; // Platform-dependent path export type ResourcePath = string; // Always POSIX @@ -156,6 +157,10 @@ export default class LinterContext { } addLintingMessage(resourcePath: ResourcePath, message: LintMessage) { + if (message.messageDetails) { + message.messageDetails = resolveLinks(message.messageDetails); + } + this.getLintingMessages(resourcePath).push(message); } From 697869c98d15821e0dec24ecb059ed08cb6b097d Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 09:07:26 +0300 Subject: [PATCH 67/90] test: Update snapshots with the new changes --- .../rules/snapshots/BestPractices.ts.md | 44 ++++++++++++------ .../rules/snapshots/BestPractices.ts.snap | Bin 1466 -> 1736 bytes 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 5904e0261..3783fd625 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -174,29 +174,37 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_2/Component.js', + filePath: 'Positive_2/manifest.json', messages: [ { - column: 9, - fatal: undefined, - line: 4, + column: 12, + line: 18, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + pos: 325, ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, { - column: 9, - fatal: undefined, - line: 4, + column: 16, + line: 29, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + pos: 551, ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, ], warningCount: 2, }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_2/Component.js', + messages: [], + warningCount: 0, + }, ] ## General: Positive_3/Component.js @@ -267,23 +275,23 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_5/Component.js', + filePath: 'Positive_5/manifest.json', messages: [ { - column: 9, - fatal: undefined, - line: 4, + column: 12, + line: 19, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + pos: 341, ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, { - column: 9, - fatal: undefined, - line: 4, + column: 16, + line: 29, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + pos: 551, ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, @@ -298,6 +306,14 @@ Generated by [AVA](https://avajs.dev). messages: [], warningCount: 0, }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_5/Component.js', + messages: [], + warningCount: 0, + }, ] ## General: Positive_6/Component.js diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 07468e0525f9e5c0558e80cc876f46f4c1200196..986a454b524e8c07507fec71f506ea4e523c2a4f 100644 GIT binary patch literal 1736 zcmV;(1~>UZRzV#kKxtA!k$04 zzQutzn;(k^00000000B+T3u)yRTTctotd4niAib;kxJoGm9&^-lXSC*Ma0soM8$?e z{R7d-&fR3{?A&E$HZiD3si+VB;V&Xmv=1UG3cmPY5d~3Eu+S&*%^&c=KM<_=WM+0Z z?vB}=WSexOZeB7ocki8h&v(vuzI*PxlAm#8?jHY%S4Ch4j<}a!FI?f7&OUy#m^A}? zUfeaBJ|GK4=?XU(KI+@PYZm=E8TiLuu`Dw%Z>J{}=m`JFAT|hK48S%@Z6$5L=b4K{ z)vMm#UeFd0fx3vUs&>*B06YNTB>?XO_y)iZ0y0z?D0OJ&sK^DxmM{DI`alE`X(k|!)4NbX3};(_VSiooZlzv$-XJn71k?<~e%(^GlPK@pg?<5wOt&=Fto{WU%L zP13Z&H}0Mbf}+1Koi5qq!@gM@&dEZ0ba-@ZBzb_3z% z&79!2%WHj$OON{^D6f#`9dp*_dFk<8q7$v@$~*&g#9mS&i?Fi3?%a8 zKrK=F+^#aLup&~db%0@hSQO;Eh-mL`_KcHfl^^q-EYvaNs*(taWNL4kOw6L4P8?!S zY%WSsmM5UHYva;p-AJ5P0e4>$xOXPN{Y+cnuFsYKQqTw3hJoHBb0;0$bhZd}>1c(s zo6Z)Yvqk7^5fZluN#}~G9qq3xwM;bYE_+uvS8S1ILeZI^dtWBtWaT8GDcO|u>w8qy zuV-mlzh)V56$9>Iz&rzer2eyQ6K}1$vXTlJtp#@qJBNQ8NJc0XPWYP*QqP%6s(X>eF+T z>Qfid>F|<8NvDf|tpubAm?mI;>H2K~K1(h{{Y1cTVRr_MG2k`^JkNl45(-fU>1P=5 z6$8#P;9>>1S^?%2;3*~6bxVU(_pY*8YFOhd)Udu(&b@~9N1Io;vu1@2j<&a}=X|t1 zqHY$+vcl&eH?_RJ1jRC^0kqk`7I*mI;);rpMc zpte`|l0Iltj&?TQ{SB;jP8)AJe-*xG!y_>TxFIh8HcN$XWXjDsB};H~IcB*pa@7); zjH0>T@~esH+v}twU$7mA&xoi*D6FU=R`P{4$Y)AHNJL>V(Gq#v6;@rjZNTRR5tv~( eRA<#ZQu}Kn)wHak20ZkSF#QYcaa1(rGynjrIa^Qw literal 1466 zcmV;r1x5NnRzVq{{ps2__600000000B+T1{*lMHK$tuGeDyZRAcYh*|6TRcE<@hfK-HlOF^Ps5GtrY5=DpuHx3|F4sd{;I3jTXA*h77R_clF z+79+6_9p3%ExNg6ci+y>e&2lWy_x5W<)ST1uXyiX63SAxc$FO!j&QksfITZJTv?0a zOfGvwR%_A`j>;@}mgn%AH!qcU_M&NW#ZS|FI#TfeC{5ZJfJp$mDY=V`!>-GhiCR~~ z!^5DhAOdY8I@oHIS_1GIfR6xt4d6EbdkDx=v!mp5#RXAPq^(@;+_@999h3y^AbOF2 zhe-z+yJ)B+7lq3!V$LZ`&@gtB*0OCCt}ERmvhJwhQ39bChRa-W`{{_c(q+pQC%Kw$ zJs9bNRxmlQZF1?V@H}1-UZ}^RCGI+wQ|TNu-2tQC0b{2v(Przx zE;qpC)If8YkGb3cm-&I_ayo)b?PeR7`UHRifJ0GyY5|`o8V$D*z2*O>fZA&SegN4YFD`a+oE0~?S zH)N9bApxHddU)v-us@?F*y+Cr_=kWY4cM;%M>XJc4ft6Hh7yq>KNXsIvLx+#)oH@H zC1f=MID@;?_K+=MTaIY9ON4BxCQPmSW2dB4>;+3KG47b`l&mYusW9#e=19d#(kWY& zx+_ekB(o(qnc{9mD35V(*(uGt(vfw~UJebjqdCk`p}1vx&Bq$(c~7vzZ7ta|lAHdB z`{$Lac?YuDx;35gcr8j7Dm9mAILa{Ja$ma{Cr}BcEJU2U4%uVKI z`RrtVCO0#hVRO}*Evmv%%1-N1l&`3@L%B(<9ZI^O0S7hUWer%=fcG`vkPiH$14e}3 zNmKfX1n^`6m`ecSHc)31z_bBeGk{x0sCjZQ+?I9@`yvItuU+9Dvs$h}n1PzxSIDd`v*EoND07>r=R-)?f zsW}1NhPat{cD&1Gta`MpHmB6^HLQe8=HC4&Q5p@2H;w z=?n3$aHI=bceE>{`*-~Gfgdn+;J7}Z$4?V;PRXvDg7FnyGEbCR=QA=;Y$x*TQSIrD zGZ(gG*)}VR;QUIM!EsI96XqBz)|KyU{F5$Ilr2Y?9cMxNJXRHo`*LW_s<%={+LX#o UbG(bMStZkd0r$A%EFUre06{R^IRF3v From f840097b6b9962ccbd71a28331f1dd067f5987e1 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 09:09:35 +0300 Subject: [PATCH 68/90] fix: Eslint --- src/linter/LinterContext.ts | 2 +- src/linter/ui5Types/bestPractices.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/linter/LinterContext.ts b/src/linter/LinterContext.ts index 352952385..afef8f218 100644 --- a/src/linter/LinterContext.ts +++ b/src/linter/LinterContext.ts @@ -160,7 +160,7 @@ export default class LinterContext { if (message.messageDetails) { message.messageDetails = resolveLinks(message.messageDetails); } - + this.getLintingMessages(resourcePath).push(message); } diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 6f90ea99d..86b3b397e 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -305,7 +305,7 @@ function extractPropsRecursive(node: ts.ObjectLiteralExpression) { } function reportResults({ - analysisResult, reporter, classDesc, manifestContent, resourcePath, context + analysisResult, reporter, classDesc, manifestContent, resourcePath, context, }: { analysisResult: AsyncInterfaceFindType; reporter: SourceFileReporter; @@ -355,7 +355,8 @@ function reportResults({ if (manifestContent) { // If the manifest.json is present, then we need to redirect the message pointers to it const {key: posInfo} = pointers[pointerKey]; - context.addLintingMessage(resourcePath.replace("Component.js", "manifest.json"), {...message, ...posInfo}); + context.addLintingMessage( + resourcePath.replace("Component.js", "manifest.json"), {...message, ...posInfo}); } else { reporter.addMessage({...message, ...{node: classDesc}}); } From c9319d98777e5121c7687b899c7cf986e149a709 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 09:12:48 +0300 Subject: [PATCH 69/90] fix: LintContext fix links resolve --- .../rules/snapshots/NoDeprecatedApi.ts.md | 2 +- .../rules/snapshots/NoDeprecatedApi.ts.snap | Bin 6736 -> 6729 bytes .../xmlTemplate/snapshots/transpiler.ts.md | 2 +- .../xmlTemplate/snapshots/transpiler.ts.snap | Bin 5366 -> 5388 bytes 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md index 9880d65ff..c288160af 100644 --- a/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md +++ b/test/lib/linter/rules/snapshots/NoDeprecatedApi.ts.md @@ -408,7 +408,7 @@ Generated by [AVA](https://avajs.dev). column: 1, line: 6, message: 'Usage of native HTML in XML Views/Fragments is deprecated', - messageDetails: '{@link topic:be54950cae1041f59d4aa97a6bade2d8 Using Native HTML in XML Views (deprecated)}', + messageDetails: 'Using Native HTML in XML Views (deprecated) (https://ui5.sap.com/1.120/#/topic/be54950cae1041f59d4aa97a6bade2d8)', ruleId: 'ui5-linter-no-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 1b59165a3fed7e39b22cf37a8483e0ac9ce4a3b8..f0bf172740a007417cd4404cdd75a275da11c2a0 100644 GIT binary patch literal 6729 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 Date: Fri, 17 May 2024 09:42:33 +0300 Subject: [PATCH 70/90] refactor: Improve messaging --- src/linter/ui5Types/bestPractices.ts | 28 +++++++++++------- .../rules/snapshots/BestPractices.ts.md | 8 ++--- .../rules/snapshots/BestPractices.ts.snap | Bin 1736 -> 1713 bytes 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 86b3b397e..0966d9b8b 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -330,23 +330,31 @@ function reportResults({ if (hasAsyncInterface !== AsyncInterfaceStatus.true) { if ([AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(rootViewAsyncFlag) || [AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(routingAsyncFlag)) { - const componentsToAddress = []; + let message = "Root View and Routing are not configured to load their modules asynchronously."; + let messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest"; + if (AsyncInterfaceStatus.parentPropNotSet !== rootViewAsyncFlag) { - componentsToAddress.push("Root View"); - } - if (AsyncInterfaceStatus.parentPropNotSet !== routingAsyncFlag) { - componentsToAddress.push("Routing"); + // sap.ui5/rootView is not set at all, so skip it in the message + message = "Routing is not configured to load its targets asynchronously."; + messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + + "\"sap.ui5/routing/config\" in the manifest."; + } else if (AsyncInterfaceStatus.parentPropNotSet !== routingAsyncFlag) { + // sap.ui5/routing/config is not set at all, so skip it in the message + message = "Root View is not configured to load its views asynchronously."; + messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + + "\"sap.ui5/rootView\" in the manifest."; } reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, ruleId: "ui5-linter-no-sync-loading", - message: `${componentsToAddress.join(" and ")} ${componentsToAddress.length > 1 ? "are" : "is"} ` + - "not configured to load targets asynchronously", - messageDetails: "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + - "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest.json", + message, + messageDetails, }); } } else { diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index 3783fd625..b17853eef 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -155,8 +155,8 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Root View and Routing are not configured to load targets asynchronously', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', + message: 'Routing is not configured to load its targets asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, @@ -222,8 +222,8 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Root View and Routing are not configured to load targets asynchronously', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest.json', + message: 'Routing is not configured to load its targets asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 986a454b524e8c07507fec71f506ea4e523c2a4f..752065b6ac9eeca99fc9e756d1ef161f0f42d4e9 100644 GIT binary patch literal 1713 zcmV;i22S}wRzVG`OlorjyYcDvEapbgtVn2j`DkjD}2-0#_t#7rnINT zBmJpeUM}ys!j;L%zz$q9A53^McgwtOEd>#%gJ^rDlW_#VaR6@t_yoWY0M-#ONaca_ePfd%BZ*ZnySuwV%RoA4InhG| ztR@Adt)R|~Hzj;?T#UL|57dQK#42q|h3|X*F0bIq@R5qh54y6ZG@ZL+ewE1Dj@WO? ziOPdD4XhO|E~r^tA}4~t92Y@k#Lgq8@7nHo{iKOHGb(jvtZ!3m+L~ZF(8h8WSPm>| zEVs6?oCTI!7d4iHZ7gSj<=~>mawrB%cBKYOr4K+Fz>YXPS%~L-rH&m$&ldkv2<>?Q zUjVoaKqp`e0h0tg69a96jCTn*OTgCz{6fG=2JB&g#Ufp`23~Q3wbm;()YyH$=?hn0 z;~Qt#Tz#Xu%THUp%QX$WD_q?7bKc+Fd_UTzH)%6w7BlH~%(NtC(lmoGX^arOXSM4a^m; zPA&|X#7+`$iqM3mtHyqh%EnIoOu%mhbTZ&J2JB|QX$G8CfS;7uly5{9u4g=_kaNrC zToP&3LUV?9#e#L*_fsQnM%hf2`#T@-3etARxgBuVlRV?OS$n+T3yVvSJDzEA zTLxU3{Yr68io@o_ly=_9u ze6TH*D%eBGz|1EzUM|(2>>ub$-I9`C-p-`b!|Ac~*7V?DI&;UMFfFrxWb0V}K>vt2 zGB7yYKfF1~M{{{c?R|1Qes?3j&Inoe{I(q>MnlQ|~or)b|b7U<_-YYFYWp_tK%e;{| z%>eH1CU9?vf&0~#z+ImZ|D&MyumuCXN#>3_lxd6qx^y(nsZ3k^x5fWWE&k)q0`+yR zuLaGSLgro2PIDGGM+Pa%$rwfZHUVeK)&Hh6Qc|WLQ$?9xp{g=XGhjOd4l`hi0k1G% zhXQ<~0Gb-BOgE{(?J6*;0^+Kno>GA!4LGj>|3roDY?bK(5mH;V&RD?QP-VJMaJN-! zt3Yp(R^mQONL;Q-E9xMCZ2)!y*cX>xl+xRGwXXDfxvtbfbfI|3!lctdzzPCV1nehZ z>gx3e1bh`=V)~VUKa1TNFu;I=40wY9AI6lJ5@dYGfQt;c!hp33aF+s1DZtB7@wT)< zs{2S;EY+!@X{uA-D%W3~`n$zD+)%T_2FKB>)$2Zv?o$_wWSQm@j=giy+V3gt#HO?YE>bT1{fN!>8h;RsR6%hz~egbrVd=tV-?aLI`Eec ztTuo?1Gr=W`2_HM0{A?!fVI0-Z51^CWt;=;+TBf}f?8g?i~9&onQXs!uW4Yd>w58~ z8&|t~t$5g_0DBf|?XGXs%{T>1aI+e-JP?^mnac~Kx!&?KiReRh(vcsr9fyyJuofsR zZn_pP1j5?F#|pAiHMB(5c7;_}QtJtLPDryD4wY3kkJL3ak!o62Zv!5>CQSbY;x0C# HnKS?Z@Jctw literal 1736 zcmV;(1~>UZRzV#kKxtA!k$04 zzQutzn;(k^00000000B+T3u)yRTTctotd4niAib;kxJoGm9&^-lXSC*Ma0soM8$?e z{R7d-&fR3{?A&E$HZiD3si+VB;V&Xmv=1UG3cmPY5d~3Eu+S&*%^&c=KM<_=WM+0Z z?vB}=WSexOZeB7ocki8h&v(vuzI*PxlAm#8?jHY%S4Ch4j<}a!FI?f7&OUy#m^A}? zUfeaBJ|GK4=?XU(KI+@PYZm=E8TiLuu`Dw%Z>J{}=m`JFAT|hK48S%@Z6$5L=b4K{ z)vMm#UeFd0fx3vUs&>*B06YNTB>?XO_y)iZ0y0z?D0OJ&sK^DxmM{DI`alE`X(k|!)4NbX3};(_VSiooZlzv$-XJn71k?<~e%(^GlPK@pg?<5wOt&=Fto{WU%L zP13Z&H}0Mbf}+1Koi5qq!@gM@&dEZ0ba-@ZBzb_3z% z&79!2%WHj$OON{^D6f#`9dp*_dFk<8q7$v@$~*&g#9mS&i?Fi3?%a8 zKrK=F+^#aLup&~db%0@hSQO;Eh-mL`_KcHfl^^q-EYvaNs*(taWNL4kOw6L4P8?!S zY%WSsmM5UHYva;p-AJ5P0e4>$xOXPN{Y+cnuFsYKQqTw3hJoHBb0;0$bhZd}>1c(s zo6Z)Yvqk7^5fZluN#}~G9qq3xwM;bYE_+uvS8S1ILeZI^dtWBtWaT8GDcO|u>w8qy zuV-mlzh)V56$9>Iz&rzer2eyQ6K}1$vXTlJtp#@qJBNQ8NJc0XPWYP*QqP%6s(X>eF+T z>Qfid>F|<8NvDf|tpubAm?mI;>H2K~K1(h{{Y1cTVRr_MG2k`^JkNl45(-fU>1P=5 z6$8#P;9>>1S^?%2;3*~6bxVU(_pY*8YFOhd)Udu(&b@~9N1Io;vu1@2j<&a}=X|t1 zqHY$+vcl&eH?_RJ1jRC^0kqk`7I*mI;);rpMc zpte`|l0Iltj&?TQ{SB;jP8)AJe-*xG!y_>TxFIh8HcN$XWXjDsB};H~IcB*pa@7); zjH0>T@~esH+v}twU$7mA&xoi*D6FU=R`P{4$Y)AHNJL>V(Gq#v6;@rjZNTRR5tv~( eRA<#ZQu}Kn)wHak20ZkSF#QYcaa1(rGynjrIa^Qw From 34f6698160a145eb4647905e4c489c1ac212a0c1 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 10:16:23 +0300 Subject: [PATCH 71/90] refactor: Improve runtime performance by checking Component.js --- src/linter/ui5Types/SourceFileLinter.ts | 4 +++- src/linter/ui5Types/bestPractices.ts | 15 ++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 6f9d8deab..bae7c1e85 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -70,7 +70,9 @@ export default class SourceFileLinter { node as (ts.PropertyAccessExpression | ts.ElementAccessExpression)); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ImportDeclaration) { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation - } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments) { + } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments && + ts.isSourceFile(this.#sourceFile) && + this.#sourceFile.fileName.endsWith("/Component.js")) { analyzeComponentJson({ node: node as ts.ExpressionWithTypeArguments, manifestContent: this.#manifestContent, diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 0966d9b8b..7fd29dedf 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -35,19 +35,12 @@ export default function analyzeComponentJson({ context: LinterContext; checker: ts.TypeChecker; }) { - let parent = node.parent; - let classDesc; - while (parent && parent.kind !== ts.SyntaxKind.SourceFile) { - if (parent.kind === ts.SyntaxKind.ClassDeclaration) { - classDesc = parent; - } - parent = parent.parent; + let classDesc = node.parent; + while (classDesc && classDesc.kind !== ts.SyntaxKind.ClassDeclaration) { + classDesc = classDesc.parent; } - if (!ts.isSourceFile(parent) || - !parent.fileName.endsWith("/Component.js") || - !classDesc || - !ts.isClassDeclaration(classDesc)) { + if (!classDesc || !ts.isClassDeclaration(classDesc)) { return; } From 1bb546dda45daf57e70a429b74011ce3ae371a6a Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 10:36:17 +0300 Subject: [PATCH 72/90] refactor: Cleanup --- src/linter/linter.ts | 2 +- src/linter/ui5Types/bestPractices.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/linter/linter.ts b/src/linter/linter.ts index 5b0283459..cc81d0cbc 100644 --- a/src/linter/linter.ts +++ b/src/linter/linter.ts @@ -93,7 +93,7 @@ export async function lintFile({ const absoluteFilePaths = resolveFilePaths(rootDir, pathsToLint); resolvedFilePaths = transformFilePathsToVirtualPaths( absoluteFilePaths, rootDir, "/", rootDir); - + // Extract the (virtual) path from the filename virBasePath = resolvedFilePaths[0].split("/").slice(0, -1).join("/"); } const reader = createReader({ diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 7fd29dedf..1d6cd19db 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -177,10 +177,6 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string hasAsyncInterface = hasAsyncInterfaceProp ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } - // undefined has ambiguous meaning in that context. - // It could mean either implicit "true" or "false". - // To distinguish whether it's been set from manifest's config - // or not set at all, we'll use null. let rootViewAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; let routingAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; let hasManifestDefinition = false; From e670ecca145946d176b2adce12ed2e452b2bd487 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 12:59:02 +0300 Subject: [PATCH 73/90] test: Add case for obsolete async flag --- .../linter/rules/BestPractices/Positive_6/manifest.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json index 63a4fffc3..f014842fc 100644 --- a/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json +++ b/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json @@ -16,7 +16,8 @@ "rootView": { "viewName": "mycomp.view.App", "type": "XML", - "id": "app" + "id": "app", + "async": true }, "routing": { From ca2115e7ad2f09cc35c64ff394a45f7d31ed6c2c Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 13:02:12 +0300 Subject: [PATCH 74/90] test: Update snapshots --- .../rules/snapshots/BestPractices.ts.md | 18 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 1713 -> 1828 bytes 2 files changed, 18 insertions(+) diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index b17853eef..eb41f2606 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -321,6 +321,24 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Positive_6/manifest.json', + messages: [ + { + column: 12, + line: 19, + message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', + messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', + pos: 341, + ruleId: 'ui5-linter-no-sync-loading', + severity: 1, + }, + ], + warningCount: 1, + }, { coverageInfo: [], errorCount: 0, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 752065b6ac9eeca99fc9e756d1ef161f0f42d4e9..93c586dc3ec225dd22d91953feef58ad3fa3dfa6 100644 GIT binary patch literal 1828 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 HnKS?Z@Jctw From 417a94b0ba2dc8554093c0668c2ca14f7d7ed3d2 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Fri, 17 May 2024 13:16:58 +0300 Subject: [PATCH 75/90] fix: Correct logic for reporting --- src/linter/ui5Types/bestPractices.ts | 4 ++-- .../rules/snapshots/BestPractices.ts.md | 8 ++++---- .../rules/snapshots/BestPractices.ts.snap | Bin 1828 -> 1858 bytes 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 1d6cd19db..4c1080372 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -324,13 +324,13 @@ function reportResults({ "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest"; - if (AsyncInterfaceStatus.parentPropNotSet !== rootViewAsyncFlag) { + if (AsyncInterfaceStatus.parentPropNotSet === rootViewAsyncFlag) { // sap.ui5/rootView is not set at all, so skip it in the message message = "Routing is not configured to load its targets asynchronously."; messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + "\"sap.ui5/routing/config\" in the manifest."; - } else if (AsyncInterfaceStatus.parentPropNotSet !== routingAsyncFlag) { + } else if (AsyncInterfaceStatus.parentPropNotSet === routingAsyncFlag) { // sap.ui5/routing/config is not set at all, so skip it in the message message = "Root View is not configured to load its views asynchronously."; messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index eb41f2606..bdfdd71f3 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -155,8 +155,8 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Routing is not configured to load its targets asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, @@ -222,8 +222,8 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 4, - message: 'Routing is not configured to load its targets asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', ruleId: 'ui5-linter-no-sync-loading', severity: 2, }, diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index 93c586dc3ec225dd22d91953feef58ad3fa3dfa6..ec361cd9e4e2d88678b46671816acb2d55bede81 100644 GIT binary patch literal 1858 zcmV-I2fg?~RzV<9US@}KS=$3>>n3anZVh3#5qR6R= z`S``K^B;={00000000B+T3u`$)fN8Eo!`VJc1R#7G}TpF8c^e1+p*Vfgj%A6R&EhQ zk!S&_qT`*r_JrBFtC?Ach$4hQzyk#YYO4rUDNUuSRS^gt;DIQj5+YSA6$$kL@zgd* zeQ2Rl)ds-}p4lIEC%ZHDVzUdZUpzB+@11+kckXw-d(J#lT6AUcuHdm>iO>mMaX0^t z@Pu!<2l>rn$qJnnapzS2uq;=kC%iCsJa7Wfsszh24DNr%wyn^*ogPYKIOsBv4%$Za0|IuE0@AkAXi=^R-&zt2UP*$+u!C5mZL9Eo=^vI=FN`0lNc>=| zWQCS{W5%z{lH-b_R=C`Fu&ax;;>iUqlQYXA2&^R$Bt{%PVfmipEw#VYY%`%ek)ps_qK#Bv>29vEmWXNFj=1Iw9##&R|TOLnmZOJx#30l*Dec(NGJ z@6|ev5Iq$Arx@B-0lW_29RNB3`w2Ksz=Ijknq>TjfM*H#69NAs;Bp3hmjO0Qbk(|e z#lx(>Ua_ae?nf+>pib@8rva&Py%zTSL4*`}wo8Ee}!h2fs* z%bqEGA@)q+bGc{chMHj=J}@`Xnqhv3Tf$DLd$W3`eXJXZVd!K)Y6sTBrQ97@wLlgSP2g1^Hpay7g&{CQI_*lxvA;N{8#d! ztT@GdVXm-PI8d0GDHOjkBP`pRnm@2OH9a+N%}>wFP0d}G;|t}AE6TzPc{D`T$rYt9 zatrYr4@)nMl#DN|(2*W@yioWht0=hR@m3e((&vE)YfI!M*IEjAN&0+mZOqxcUo%#| zW~9Bb0b3en7@2i%G;Fvmc-iutk_f^i%zo7s3wGmnch#AlaN{{mcyc0o^@LlqO>(OQ zVnz5)c(RT(OQD*qbe?hVry-jK0rzFg<}(CDyXtiUqCK^Z0pDi8kCL+4=t5c#^jT0| z)nfMs>bc{A^y1l_?oClf#%`|ge7_}g7te|(cVTlRGbvC2T>-|GG-hre#7t@1(%GM{ zRvP|%htlw8^OORdR)Dh#@RkBR91*$($Yp+>#Yul-eo1nSc6eJ^wU9^hR{a;-E7^z;*)i1RNz`W%c?w0{)ntiuyMJ z|Bbq@sPG2r=(RFp}^n+$l10T&r?l>&TI0ag^?2_?~WYnM>>qB1C1tl17( ztiLFqJd5>ypI5l2WrbbJ+dI`yT;85k2Su`U_$1_}p4XS5Se8}5Q-QnH&B)cYw~eH< zjdoT@52y{!_=DP1NTdOV23)f$YYu6^dm3<$4*XmP-q14@(tmW||2nYK045FKf&o-a z;87EJ&D_Ks-;SXQ+W2(Ot-~DO7eod1J;#^zQJZnaXR$hWDZ|y`;e!KHohx+EHNWh! zI!7%ld~IN=a~(ct`&;h|%*cmErMb~{l;(`&09Pu&ml6Y*ol{C*tJUb5_d;nTSbwbm zzf*wo3UEOIo>YM^YrsJb2(k-xPiep@4R}cd-mGhYZ|T4}9r#~T18f-v@xkWv{s!^Q zO2R1< wqRhW7N{%P&wxsyJfR{yRMUks9t8@@{wSZvR_CyyKy99xc0Ebv3Ka@BC07<`x)&Kwi literal 1828 zcmV+<2iy2TRzV^M!r*HDaOkM|w zUR|K-<{yg)00000000B+T3u`$)fN8Eo!`Vx?2tgB&{S6`G$7(#+p*Vfl+r{=id-Uy zkkSGYYR5Zw?Fq9ptC_n_B8V!KsObX@D5#(aRUu8KstD9dJhTr*D3uVYKmv&;#1k}B zJkWxKAgE8x&i-h3vb$q1HoGC~7tie7d*|Hqo%@|{&zbYNS=Y}#8lL{WkdAc4QGSo` zL}0l)`F&!}lFowo`B-|dpD*~H@MP+6=!BkC2ErP%g_WDInMjxq&ePJkP zNz2`z@GUdvxZniFAc#la(1;5pu0<3r5`H!2NoY#dYT z#@b*x-p6tYSdRBJmOJ`bE&S@g|-N$kXSWfpMmIwXNSya75)t42^R{{L%>h-MzOfDA7 z2Rp^GWXiID*}`3sb#i6EBzBg7bA&c5U32!IsN!t%V*>t5z#s$eV8A{GoM*tx3h-|w zG36UE!}YB17V}=kovUJ_TI9~?&R7#0Q(easm3eAx%&54jdjG=*{GxQcIqrnq^Ci#v zUe1{-2Eyjj=dN$r+>s%dRxl@I$gS|0mz@uM&o74Vu~cmFwUx#9328ZQSoxS;#-UK~ zJ#|z00pGGqPrYMa%0jp^oh~|)sn9B2hB1yyZDL5z4qP z^q}a98M}JBx#&!exY5H$Jb$G0j1jl&g!mB%#exVNd8~pUYeOMPWjf>dHz9`w0l!R^ z!xsoBot8HUD4mtH4EQkvei4_$Mhh}J(Pg2ysm|{;*bj%k7g=|%Go@H^c5R23x-ErU zL{?d1`W}C59&Exr2r5eu5&nmz<1$b2f-cx{6DzIJy z(i$+YwI^+p%wKE3X$^Qu11@R6<2qm(z-;+{10)-jV?KGhKnZF(F>3pl@R<26~&!oz#@+i~ojn)TArZ z7yo_ne?yD^q+X!Dx%;)Cjwxi>1#OdFV22D+l9LIF_ICtas8s*k(nwjE{*9{2^a|CK zX@&v281OIy78r1b0lO98Ed|ijL}hxr3f!dvGb$jiI_e1(nACua8t}ikuwAM$T_Hm1 ztJXyem~T{>t`yvT)!Hr4+oYAG*AmQ+>e7lj0bnP9eE{xHN-s+J*LSV1^xH~ZX@KaR z(j|+M&Hw@H2uKrfkbs4&*MBD9pUEYr{}AwbX*vVO8So$jo@Kya5=u-a8SgUSJqBE1 zz$OK_TLBgn;OV${Tiqhny`uC=b!xInb?R;9>sP0~>hcb^)a|fEJ9>lqwcF97YOhF^ zCa-WD=y-n#ie+8}JQX;qu0##4acrQ?*kE&obV99i#y`}WLLvA-V3@Q$9SkUrCaFLhvp0gM{JWdkUfz>_BMy19b2yY+n)wESh9L;c#_4Wfd&Ub{ Date: Fri, 17 May 2024 15:51:48 +0300 Subject: [PATCH 76/90] test: Add test cases for single async flags --- .../BestPractices/Positive_7/Component.js | 9 ++++ .../BestPractices/Positive_7/manifest.json | 22 ++++++++ .../BestPractices/Positive_8/Component.js | 9 ++++ .../BestPractices/Positive_8/manifest.json | 39 ++++++++++++++ .../rules/snapshots/BestPractices.ts.md | 50 ++++++++++++++++++ .../rules/snapshots/BestPractices.ts.snap | Bin 1858 -> 1970 bytes 6 files changed, 129 insertions(+) create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_7/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_8/Component.js create mode 100644 test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js new file mode 100644 index 000000000..65390c90e --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.Component", { + metadata: { + manifest: "json" + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json new file mode 100644 index 000000000..2aa1076da --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json @@ -0,0 +1,22 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + } + } +} diff --git a/test/fixtures/linter/rules/BestPractices/Positive_8/Component.js b/test/fixtures/linter/rules/BestPractices/Positive_8/Component.js new file mode 100644 index 000000000..65390c90e --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_8/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.Component", { + metadata: { + manifest: "json" + }, + }); +}); diff --git a/test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json b/test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json new file mode 100644 index 000000000..2ec69c853 --- /dev/null +++ b/test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json @@ -0,0 +1,39 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/BestPractices.ts.md index bdfdd71f3..63a6d4f32 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/BestPractices.ts.md @@ -358,3 +358,53 @@ Generated by [AVA](https://avajs.dev). warningCount: 1, }, ] + +## General: Positive_7/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Positive_7/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View is not configured to load its views asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/rootView" in the manifest.', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: Positive_8/Component.js + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Positive_8/Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Routing is not configured to load its targets asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.snap b/test/lib/linter/rules/snapshots/BestPractices.ts.snap index ec361cd9e4e2d88678b46671816acb2d55bede81..937f75a6abbf566f47dfc80d53150ec439f442af 100644 GIT binary patch literal 1970 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 From 6d63c566d020e33c4b9e49f878babaa6ea2b0717 Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 20 May 2024 09:44:58 +0300 Subject: [PATCH 77/90] fix: Report missing manifest definition only when there is a manifest.json --- src/linter/ui5Types/bestPractices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/bestPractices.ts index 4c1080372..203abe562 100644 --- a/src/linter/ui5Types/bestPractices.ts +++ b/src/linter/ui5Types/bestPractices.ts @@ -305,7 +305,7 @@ function reportResults({ }) { const {hasAsyncInterface, routingAsyncFlag, rootViewAsyncFlag, hasManifestDefinition} = analysisResult; - if (!hasManifestDefinition) { + if (!hasManifestDefinition && !!manifestContent) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Warning, From 77e53696edec0ac68f0cc05de7c0fa804991f96b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Mon, 27 May 2024 11:12:05 +0300 Subject: [PATCH 78/90] deps: Rebuild api-json deps from UI5 1.120.13 --- README.md | 4 ++-- resources/api-extract.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 901529a79..ddc350173 100644 --- a/README.md +++ b/README.md @@ -106,11 +106,11 @@ The extracted and generated metadata is stored within the repository under the ` Regular updates to the metadata are necessary to ensure that the data is compatible with the corresponding UI5 type definitions. ```sh -npm run update-pseudo-modules-info -- $DOMAIN_NAME/com/sap/ui5/dist/sapui5-sdk-dist/1.120.12/sapui5-sdk-dist-1.120.12-api-jsons.zip 1.120.12 +npm run update-pseudo-modules-info -- $DOMAIN_NAME/com/sap/ui5/dist/sapui5-sdk-dist/1.120.13/sapui5-sdk-dist-1.120.13-api-jsons.zip 1.120.13 ``` ```sh -npm run update-semantic-model-info -- $DOMAIN_NAME/com/sap/ui5/dist/sapui5-sdk-dist/1.120.12/sapui5-sdk-dist-1.120.12-api-jsons.zip 1.120.12 +npm run update-semantic-model-info -- $DOMAIN_NAME/com/sap/ui5/dist/sapui5-sdk-dist/1.120.13/sapui5-sdk-dist-1.120.13-api-jsons.zip 1.120.13 ``` diff --git a/resources/api-extract.json b/resources/api-extract.json index 236c5ee08..dd0177b24 100644 --- a/resources/api-extract.json +++ b/resources/api-extract.json @@ -1,7 +1,7 @@ { "framework": { "name": "SAPUI5", - "version": "1.120.12" + "version": "1.120.13" }, "defaultAggregations": { "sap.ca.ui.CustomerControlListItem": "content", From 0b01e1b6b8edd0f8a75c72bb05edb89d3ca36b0f Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Thu, 23 May 2024 15:28:15 +0200 Subject: [PATCH 79/90] refactor(tests): Rename BestPractices to AsyncComponentFlags, use dir name as test name Using the dir name as test name allows for use of 'only_' modifiers to control which tests are executed. --- .../Negative_01}/Component.js | 0 .../Negative_01}/manifest.json | 0 .../Negative_02}/Component.js | 0 .../Negative_02}/manifest.json | 0 .../Negative_03}/Component.js | 0 .../Negative_04}/Component.js | 0 .../Negative_05}/Component.js | 0 .../Negative_05}/ParentComponent.js | 0 .../Negative_05}/manifest.json | 0 .../Negative_06}/Component.js | 0 .../Negative_06}/ParentComponent.js | 0 .../Negative_06}/manifest.json | 0 .../Negative_07}/Component.js | 0 .../Negative_07}/manifest.json | 0 .../Negative_08}/Component.js | 0 .../Negative_08}/manifest.json | 0 .../Positive_01}/Component.js | 0 .../Positive_01}/manifest.json | 0 .../Positive_02}/Component.js | 0 .../Positive_02}/manifest.json | 0 .../Positive_03}/Component.js | 0 .../Positive_04}/Component.js | 0 .../Positive_05}/Component.js | 0 .../Positive_05}/ParentComponent.js | 0 .../Positive_05}/manifest.json | 0 .../Positive_06}/Component.js | 0 .../Positive_06}/manifest.json | 0 .../Positive_07}/Component.js | 0 .../Positive_07}/manifest.json | 0 .../Positive_08}/Component.js | 0 .../Positive_08}/manifest.json | 0 test/lib/linter/_linterHelper.ts | 21 ++--- ...estPractices.ts => AsyncComponentFlags.ts} | 0 ...ctices.ts.md => AsyncComponentFlags.ts.md} | 80 +++++++++--------- .../snapshots/AsyncComponentFlags.ts.snap | Bin 0 -> 1879 bytes .../rules/snapshots/BestPractices.ts.snap | Bin 1970 -> 0 bytes 36 files changed, 51 insertions(+), 50 deletions(-) rename test/fixtures/linter/rules/{BestPractices/Negative_1 => AsyncComponentFlags/Negative_01}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_1 => AsyncComponentFlags/Negative_01}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_2 => AsyncComponentFlags/Negative_02}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_2 => AsyncComponentFlags/Negative_02}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_3 => AsyncComponentFlags/Negative_03}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_4 => AsyncComponentFlags/Negative_04}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_5 => AsyncComponentFlags/Negative_05}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_5 => AsyncComponentFlags/Negative_05}/ParentComponent.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_5 => AsyncComponentFlags/Negative_05}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_6 => AsyncComponentFlags/Negative_06}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_6 => AsyncComponentFlags/Negative_06}/ParentComponent.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_6 => AsyncComponentFlags/Negative_06}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_7 => AsyncComponentFlags/Negative_07}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_7 => AsyncComponentFlags/Negative_07}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_8 => AsyncComponentFlags/Negative_08}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Negative_8 => AsyncComponentFlags/Negative_08}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_1 => AsyncComponentFlags/Positive_01}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_1 => AsyncComponentFlags/Positive_01}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_2 => AsyncComponentFlags/Positive_02}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_2 => AsyncComponentFlags/Positive_02}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_3 => AsyncComponentFlags/Positive_03}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_4 => AsyncComponentFlags/Positive_04}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_5 => AsyncComponentFlags/Positive_05}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_5 => AsyncComponentFlags/Positive_05}/ParentComponent.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_5 => AsyncComponentFlags/Positive_05}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_6 => AsyncComponentFlags/Positive_06}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_6 => AsyncComponentFlags/Positive_06}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_7 => AsyncComponentFlags/Positive_07}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_7 => AsyncComponentFlags/Positive_07}/manifest.json (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_8 => AsyncComponentFlags/Positive_08}/Component.js (100%) rename test/fixtures/linter/rules/{BestPractices/Positive_8 => AsyncComponentFlags/Positive_08}/manifest.json (100%) rename test/lib/linter/rules/{BestPractices.ts => AsyncComponentFlags.ts} (100%) rename test/lib/linter/rules/snapshots/{BestPractices.ts.md => AsyncComponentFlags.ts.md} (84%) create mode 100644 test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap delete mode 100644 test/lib/linter/rules/snapshots/BestPractices.ts.snap diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_1/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_1/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_2/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_2/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_3/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_3/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_4/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_4/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_5/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_5/ParentComponent.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_5/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_6/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_6/ParentComponent.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_6/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_7/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_7/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_7/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Negative_8/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_8/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Negative_8/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Negative_8/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_1/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_1/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_2/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_2/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_3/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_3/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_4/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_4/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_5/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_5/ParentComponent.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_5/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_6/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_6/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_6/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_7/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_7/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/manifest.json diff --git a/test/fixtures/linter/rules/BestPractices/Positive_8/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_8/Component.js rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js diff --git a/test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/manifest.json similarity index 100% rename from test/fixtures/linter/rules/BestPractices/Positive_8/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/manifest.json diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 3de488eb5..724a40fea 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -68,12 +68,12 @@ export function createTestsForFixtures(fixturesPath: string) { if (!testFiles.length) { throw new Error(`Failed to find any fixtures in directory ${fixturesPath}`); } - if (fixturesPath.includes("BestPractices")) { - const dirName = fixturesPath.split("/").pop(); + if (fixturesPath.includes("AsyncComponentFlags")) { + const dirName = path.basename(fixturesPath); testDefinition({ - testName: `${path.basename(fixturesPath)}/Component.js`, + testName: dirName, namespace: "mycomp", - fileName: `${dirName}/Component.js`, + fileName: dirName, fixturesPath, // Needed, because without a namespace, TS's type definition detection // does not function properly for the inheritance case @@ -134,13 +134,14 @@ function testDefinition( includeMessageDetails: true, }); assertExpectedLintResults(t, res, fixturesPath, filePaths); - res.forEach((results) => { - const chunks = testName.split("/").slice(0, -1); - - if (chunks.length > 0) { - results.filePath = path.posix.join(...chunks, path.basename(results.filePath)); + res.forEach((result) => { + const resultFileName = path.basename(result.filePath); + if (resultFileName === fileName) { + // Use "clean" testName instead of the fileName which might contain modifiers like "only_" + result.filePath = testName; } else { - results.filePath = testName; + // Use only the file name without the directory (which might contain modifiers) + result.filePath = resultFileName; } }); t.snapshot(res); diff --git a/test/lib/linter/rules/BestPractices.ts b/test/lib/linter/rules/AsyncComponentFlags.ts similarity index 100% rename from test/lib/linter/rules/BestPractices.ts rename to test/lib/linter/rules/AsyncComponentFlags.ts diff --git a/test/lib/linter/rules/snapshots/BestPractices.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md similarity index 84% rename from test/lib/linter/rules/snapshots/BestPractices.ts.md rename to test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index 63a6d4f32..e8131b541 100644 --- a/test/lib/linter/rules/snapshots/BestPractices.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -1,10 +1,10 @@ -# Snapshot report for `test/lib/linter/rules/BestPractices.ts` +# Snapshot report for `test/lib/linter/rules/AsyncComponentFlags.ts` -The actual snapshot is saved in `BestPractices.ts.snap`. +The actual snapshot is saved in `AsyncComponentFlags.ts.snap`. Generated by [AVA](https://avajs.dev). -## General: Negative_1/Component.js +## General: Negative_01 > Snapshot 1 @@ -13,13 +13,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_1/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_2/Component.js +## General: Negative_02 > Snapshot 1 @@ -28,13 +28,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_2/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_3/Component.js +## General: Negative_03 > Snapshot 1 @@ -43,13 +43,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_3/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_4/Component.js +## General: Negative_04 > Snapshot 1 @@ -58,13 +58,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_4/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_5/Component.js +## General: Negative_05 > Snapshot 1 @@ -73,7 +73,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_5/ParentComponent.js', + filePath: 'ParentComponent.js', messages: [], warningCount: 0, }, @@ -81,13 +81,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_5/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_6/Component.js +## General: Negative_06 > Snapshot 1 @@ -96,7 +96,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_6/ParentComponent.js', + filePath: 'ParentComponent.js', messages: [], warningCount: 0, }, @@ -104,13 +104,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_6/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_7/Component.js +## General: Negative_07 > Snapshot 1 @@ -119,13 +119,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_7/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Negative_8/Component.js +## General: Negative_08 > Snapshot 1 @@ -134,13 +134,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Negative_8/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Positive_1/Component.js +## General: Positive_01 > Snapshot 1 @@ -149,7 +149,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 1, fatalErrorCount: 0, - filePath: 'Positive_1/Component.js', + filePath: 'Component.js', messages: [ { column: 9, @@ -165,7 +165,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_2/Component.js +## General: Positive_02 > Snapshot 1 @@ -174,7 +174,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_2/manifest.json', + filePath: 'manifest.json', messages: [ { column: 12, @@ -201,13 +201,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_2/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Positive_3/Component.js +## General: Positive_03 > Snapshot 1 @@ -216,7 +216,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 1, fatalErrorCount: 0, - filePath: 'Positive_3/Component.js', + filePath: 'Component.js', messages: [ { column: 9, @@ -232,7 +232,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_4/Component.js +## General: Positive_04 > Snapshot 1 @@ -241,7 +241,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_4/Component.js', + filePath: 'Component.js', messages: [ { column: 9, @@ -266,7 +266,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_5/Component.js +## General: Positive_05 > Snapshot 1 @@ -275,7 +275,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_5/manifest.json', + filePath: 'manifest.json', messages: [ { column: 12, @@ -302,7 +302,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_5/ParentComponent.js', + filePath: 'ParentComponent.js', messages: [], warningCount: 0, }, @@ -310,13 +310,13 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_5/Component.js', + filePath: 'Component.js', messages: [], warningCount: 0, }, ] -## General: Positive_6/Component.js +## General: Positive_06 > Snapshot 1 @@ -325,7 +325,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_6/manifest.json', + filePath: 'manifest.json', messages: [ { column: 12, @@ -343,7 +343,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'Positive_6/Component.js', + filePath: 'Component.js', messages: [ { column: 9, @@ -359,7 +359,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_7/Component.js +## General: Positive_07 > Snapshot 1 @@ -368,7 +368,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 1, fatalErrorCount: 0, - filePath: 'Positive_7/Component.js', + filePath: 'Component.js', messages: [ { column: 9, @@ -384,7 +384,7 @@ Generated by [AVA](https://avajs.dev). }, ] -## General: Positive_8/Component.js +## General: Positive_08 > Snapshot 1 @@ -393,7 +393,7 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 1, fatalErrorCount: 0, - filePath: 'Positive_8/Component.js', + filePath: 'Component.js', messages: [ { column: 9, diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..59bc28ea4830ebf2476fa52297e3b74aa256cd28 GIT binary patch literal 1879 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 Date: Thu, 23 May 2024 15:31:49 +0200 Subject: [PATCH 80/90] refactor: Rename bestPractices module to asyncComponentFlags, also check TS-Components --- src/linter/ui5Types/SourceFileLinter.ts | 4 ++-- .../ui5Types/{bestPractices.ts => asyncComponentFlags.ts} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/linter/ui5Types/{bestPractices.ts => asyncComponentFlags.ts} (100%) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index bae7c1e85..bfe870646 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -1,7 +1,7 @@ import ts, {Identifier} from "typescript"; import SourceFileReporter from "./SourceFileReporter.js"; import LinterContext, {ResourcePath, CoverageCategory, LintMessageSeverity} from "../LinterContext.js"; -import analyzeComponentJson from "./bestPractices.js"; +import analyzeComponentJson from "./asyncComponentFlags.js"; interface DeprecationInfo { symbol: ts.Symbol; @@ -72,7 +72,7 @@ export default class SourceFileLinter { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments && ts.isSourceFile(this.#sourceFile) && - this.#sourceFile.fileName.endsWith("/Component.js")) { + (this.#sourceFile.fileName.endsWith("/Component.js") || this.#sourceFile.fileName.endsWith("/Component.ts"))) { analyzeComponentJson({ node: node as ts.ExpressionWithTypeArguments, manifestContent: this.#manifestContent, diff --git a/src/linter/ui5Types/bestPractices.ts b/src/linter/ui5Types/asyncComponentFlags.ts similarity index 100% rename from src/linter/ui5Types/bestPractices.ts rename to src/linter/ui5Types/asyncComponentFlags.ts From d2eabaa65b2d98884122d586c5a8edf1026789f9 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Thu, 23 May 2024 15:50:05 +0200 Subject: [PATCH 81/90] test(AsyncComponentFlags): Add more test cases Snapshots reflect unexpected behavior. Negative tests should have no findings while positive tests should show findings. --- .../Negative_09/Component.js | 10 ++ .../Negative_09/manifest.json | 45 +++++++ .../Negative_10/Component.js | 5 + .../Negative_10/ParentComponent.js | 10 ++ .../Negative_10/manifest.json | 45 +++++++ .../Negative_11/Component.ts | 7 ++ .../Negative_11/ParentComponent.ts | 4 + .../Negative_11/manifest.json | 45 +++++++ .../Positive_09/Component.js | 5 + .../Positive_09/ParentComponent.js | 9 ++ .../Positive_09/manifest.json | 45 +++++++ .../rules/snapshots/AsyncComponentFlags.ts.md | 114 ++++++++++++++++++ .../snapshots/AsyncComponentFlags.ts.snap | Bin 1879 -> 2047 bytes 13 files changed, 344 insertions(+) create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/manifest.json create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/manifest.json create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/manifest.json diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js new file mode 100644 index 000000000..021cd32da --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js @@ -0,0 +1,10 @@ +sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/library"], function (UIComponent, coreLib) { + "use strict"; + + return UIComponent.extend("mycomp.Component", { + "metadata": { + "interfaces": [coreLib.IAsyncContentCreation], + "manifest": "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js new file mode 100644 index 000000000..d239b16df --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js @@ -0,0 +1,5 @@ +sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { + "use strict"; + + return ParentComponent.extend("mycomp.Component", {}); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js new file mode 100644 index 000000000..9f2b206b2 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js @@ -0,0 +1,10 @@ +sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/library"], function (UIComponent, coreLib) { + "use strict"; + + return UIComponent.extend("mycomp.ParentComponent", { + metadata: { + interfaces: [coreLib.IAsyncContentCreation], + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts new file mode 100644 index 000000000..4911f0251 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts @@ -0,0 +1,7 @@ +import ParentComponent from "mycomp/ParentComponent"; + +export default class Component extends ParentComponent { + static metadata = { + manifest: "json", + }; +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts new file mode 100644 index 000000000..10ef4a980 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts @@ -0,0 +1,4 @@ +import { IAsyncContentCreation } from "sap/ui/core/library"; + +export default class Component implements IAsyncContentCreation { +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js new file mode 100644 index 000000000..d239b16df --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js @@ -0,0 +1,5 @@ +sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { + "use strict"; + + return ParentComponent.extend("mycomp.Component", {}); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js new file mode 100644 index 000000000..58668af47 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.ParentComponent", { + metadata: { + manifest: "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/manifest.json new file mode 100644 index 000000000..63a4fffc3 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/manifest.json @@ -0,0 +1,45 @@ +{ + "_version": "1.12.0", + + "sap.app": { + "id": "mycomp", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + + "sap.ui5": { + "rootView": { + "viewName": "mycomp.view.App", + "type": "XML", + "id": "app" + }, + + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "mycomp.view", + "controlId": "app", + "controlAggregation": "pages" + }, + "routes": [ + { + "pattern": "", + "name": "main", + "target": "main" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main" + } + } + } + } +} diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index e8131b541..c573268d7 100644 --- a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -140,6 +140,87 @@ Generated by [AVA](https://avajs.dev). }, ] +## General: Negative_09 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + ] + +## General: Negative_10 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'ParentComponent.js', + messages: [], + warningCount: 0, + }, + ] + +## General: Negative_11 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'ParentComponent.ts', + messages: [], + warningCount: 0, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'Component.ts', + messages: [], + warningCount: 0, + }, + ] + ## General: Positive_01 > Snapshot 1 @@ -408,3 +489,36 @@ Generated by [AVA](https://avajs.dev). warningCount: 0, }, ] + +## General: Positive_09 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 4, + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 0, + }, + { + coverageInfo: [], + errorCount: 0, + fatalErrorCount: 0, + filePath: 'ParentComponent.js', + messages: [], + warningCount: 0, + }, + ] diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap index 59bc28ea4830ebf2476fa52297e3b74aa256cd28..7fd583622ba14925bf8816fc3b79b4293490cf24 100644 GIT binary patch literal 2047 zcmV?;n-^4Ck`h*% zYzRbYK`FjsVQXZ&*)Wnc$I861(0 z^sM4R^O&5s0((h5Ha=ndj%l*Y%AkrBjJgn`&5 z#3KUUCsc&KU2Ms@OVYFE<&0Bs5yR{dO1*5e^gP!)0r zi}JV?EHv6Y;{~v|s7bLQ{{@CF%Rty!0d0Y+1HE$9Cpdx0GIGJ9U-qR+ni_ zWgRfvlVCP*nC(q48#v4+6U+tk4H0EU3w0v;2v5(8mcq@EXWQNRxbToaH|U{Zl&O5|0&4f>BO{YC$-8_vREV!Pzvs&j=)~gyTTQ$ms&O@U`)U%0YSW$ z{hEMp3izIYUkOkYm{MRis%4Ef>(KN z*u!zxx7%i0lRZ(gCrW&5;$v^k$KIrr7KZ^+^LN6>u5(ZHoPcm4y(%DFMydkiHhTwSft+{0>p=BA%g;b|3KRN;yWk8AKB4L+d5iJ09{TBJQ4KBL2V9WLomFyNmC zY)iqBRP3(4Gx2ZfK<;;SCU@l-Mq~MJw3z^X)2=h8%vZ>+c>-k26SCwk$qJp_WW^{c z)_Jesxus6b*V;J<8Bf_AorJY$XJf0_73qt*=vF(RDGx{G%57t4u@1OLI>3ET4BTJo z3*4)H;DCZYs`L!>4sN-{d9Ot2CrUq2`iau-R_V7mj%W<`KMCG7rSwe5cF8EAjEqsT z&kA_17BuWgD^*4MvZyQ4zlw$;eL#VUT2knY0$&P~L@K#EsG-by!Upm-ei>;X+Q|R^NTd>F0eOR=Yg>+ue<= zIa@WXZ8Q<`fYzgE+7S(oYVZlI7tyrUWkVgxwzSqfb6TAeE@%zS^E(axsDY+~sl!zr zP8qOdz$-?q=6T(KHw<{&fZ-HeNx^Iy&ZOambPuC&I}%-U`vWp3lPKK(iLU8;6t2bP z7vsN!m>g?&V9?ok$+0hYnH&>M!+K@ICC7f+{itHXlwoG<-`yV;6bdRBDjghtBkVI$ zO_4R8XVrS#^Xv@`c20#$DqL0Ja~h;|_@EA-jL(xjp~F);T+rdN4!_W0mjN#s@Y|?^ z-;{XhjZN15_0YYFl8?_gxnemlO{)Qi>C0R_e(Y9&TD|bs1JJHu zUkN9deVN~F&Xt33c7*}?ye!y`%&&@7kNRdw23F{!>b>d=!uy**u=4q_HdE|Y++~Za zaq7R4q}4zstjuUJIs%UWqIJvLa dW70|P>m~Q~k`qSB38S`r{Xb7(1Uwc}002l&@)rOA literal 1879 zcmV-d2dMZ#RzVHy@}}5(!&P zHUv^JAaZx^nc17%xo5ri%x)JdD2if1Db|X#A|wdn4=dzHe;HBIQc#Hg5s}i?_=QNJ zrJ?;15u1DGBQrO%_im<{%#OYLXXnnD^YuRGJnzHv-jk&{M;1@`zdR+BtsJ2a2v>Nf zvzH$dWmDOU;^DDz+jq?ce_ks8@spNiD)T||Btr(lAITEB1Hc4;EyUPN^m{zdTqdOP zDVNKEtOp?=LxkMf=#*Ik@F;-a0(c9+X8>{p*iPyL8MAZ8MNtvj{5U*346+f#0NF&y z{RH?CVIcZuvY{v!g=dz)oE1Al4?oIerwq!fv zu&L&obMBLs1?dV`<&XQ}isoBZl&uKgH_O7046|X$^jzC5x6hPqiydo=U3;6>(iVf+ zM2gwKVYV~HY~V1POfefc%%-lyjGk}7jEw=92Jqt~+-Qi~eYK85ggh1eCn1FI0{9bv zF98??*g=4Y39y_1VU}cGCcr5IyhDKV1jtZek^+Zlq^rIH`j625qJP6-(-W?`;tV`X zyFCNVt-apotzCJr|Je1Wx;xm>HY27jv$_j0onDCaLZlbs@`c!yX7z!~>bq0S1_ZOi z(zjQ17PMQgDQ0H?d=6lk0JpCevxD7Y7A&PVpxM0vjnL;V4g3N@47)ZX{0gZ@IQtg@ zd`=MLd)!QcJrsD20`D<^X^BZW6Ir-Xluotc)?>IX(yE6s44*O^BW;>vyQ1Dti?n6x zVQM@dIwGawKefdYH(iS#kyT~8Wo~+cyHfF@bW3)*>IsW0$sK80T+IvH;}vOD9pQ7+ zUv`W0o^)l^cb4;!**4W@+b@)9JAVCZ`Yn$7g5T59mESK-E13AUd8HQoy@f*6p33{? zLcS;~h4K9O#8}~$f|3h%u`s=BdTx5>^yK7panGbMEpvSL&bjf4@!jU`iOF5#ySC@~ zOl83l72zr#3{kc7Md^wBOgQ5{>8e0>c*0b+bh+&+;g!sy;I_+Kj~JI8_l2r$k(V5^ z?DLZJ__o@ZQw6UUtU@hF+rj|0G)fhObz3m3nisrcx^_wUDhjh#b;OL-c-&gGr$(J{ zO{1b3+=8yZ*4VUyxcZx5FaC2Ly*PM<$*Bc#6*f$jTCj~CjINEI= zBpcJVuJg&&S>xpHXN{AaeS!hcFyJ)?oMpfx8t|P4+@u3X^myjZlB}l#KhuF1b>OrP zlnmfs2Cyju9LPkv8&^sE8)C@)hIn$P&tfEz|3+E~(C2o8IfWIHUF!kJ^CO}n7ez>C zmsv4NiVfZ?d9o76e4Ud65y_MtnFPSt9^K#xfu9o_=S{-Gs(Xp;c; z0@x2=HYts;kk*bh&7xn|&7vVfK13*=g5)wpfXxIb5a2KY776ew0p3pbjXop5*90&w z39u0g9HhWw6!=YoZLt%;C3v>v%>2Q=WI20Wnk!cA*$8;WV$&{^}$X$?v^sWmmvryB5; z2536Kb>N&195aAL19;O&)I1*;z()pf!2og@;A{q%%>pN~z^mCFx^P=kU32XXnWL!- z_kW^m`tHJYc+t!Feh`aeSCU#S@40KQIQEM!i({l^TW_wp;@JD$?<&Ej3@T&)xr)kI zCOQBZU@*ia{HE277@4rx|dL0YBG(tPb3&0}mzF$sW~#Cv@PX z4xG_}Pjq0r0laPie~Tvgb!moP+hpC}4Bac2d~C)oI#o+>vk3?HMX})@%Mhsci@zGM z9&DpPzGOQNpA(_YF09Z_uKL2-!RM+fI9-7uZ;6ua3aibl9`SiaC^N`Wja9{iaAOMy zre%$;aKx@AU3Pd4l>Iv`S`B2;>O~5?%z%#)Eakpk$Ga{Ut?JjJL!HW2K3}xOQkONV zzYb`PYNdP>`PJmKB006kzl Date: Fri, 24 May 2024 11:10:07 +0200 Subject: [PATCH 82/90] refactor(asyncComponentFlags): Remove usage of internal API, improve string extraction --- src/linter/ui5Types/asyncComponentFlags.ts | 100 ++++++++++++++------- 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 203abe562..77a399085 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -122,34 +122,54 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { }); } +function isCoreImportDeclaration(statement: ts.Node): statement is ts.ImportDeclaration { + return ts.isImportDeclaration(statement) && + ts.isStringLiteral(statement.moduleSpecifier) && + statement.moduleSpecifier.text === "sap/ui/core/library"; +} + function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatus { - while (importDeclaration && importDeclaration.kind !== ts.SyntaxKind.SourceFile) { - importDeclaration = importDeclaration.parent; - } + const sourceFile = importDeclaration.getSourceFile(); + + let coreLibImports: ts.ImportDeclaration[] | undefined; + if (sourceFile.isDeclarationFile) { + let moduleDeclaration: ts.ModuleDeclaration | undefined; + while (!moduleDeclaration && importDeclaration.kind !== ts.SyntaxKind.SourceFile) { + if (ts.isModuleDeclaration(importDeclaration)) { + moduleDeclaration = importDeclaration; + } else { + importDeclaration = importDeclaration.parent; + } + } - // @ts-expect-error imports is part of SourceFileObject - const moduleImports = importDeclaration?.imports as ts.Node[]; - const coreLib = moduleImports?.find((importModule) => { - return importModule.getText() === "\"sap/ui/core/library\""; - }) as ts.StringLiteral | undefined; + if (moduleDeclaration?.body?.kind === ts.SyntaxKind.ModuleBlock) { + coreLibImports = moduleDeclaration.body.statements.filter(isCoreImportDeclaration); + } + } else { + coreLibImports = sourceFile.statements.filter(isCoreImportDeclaration); + } - let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; - if (coreLib && ts.isImportDeclaration(coreLib.parent)) { - if (coreLib.parent.importClause?.namedBindings && - coreLib.parent.importClause.namedBindings.kind === ts.SyntaxKind.NamedImports) { - const hasAsyncImport = coreLib.parent.importClause.namedBindings.elements.some( + // let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; + if (!coreLibImports) { + return AsyncInterfaceStatus.propNotSet; + } + const hasAsyncImport = coreLibImports.some((importDecl) => { + const importClause = importDecl.importClause; + if (!importClause) { + return; + } + if (!importClause.namedBindings) { + // Example: import "sap/ui/core/library"; or import library from "sap/ui/core/library"; + } else if (ts.isNamedImports(importClause.namedBindings)) { + // Example: import { IAsyncContentCreation } from "sap/ui/core/library"; + return importClause.namedBindings.elements.some( (namedImport) => namedImport.getText() === "IAsyncContentCreation"); - - hasAsyncInterface = hasAsyncImport ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } else { - const implementsAsyncInterface = - coreLib.parent.importClause?.name?.getText() === "IAsyncContentCreation"; - - hasAsyncInterface = implementsAsyncInterface ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + // Example: import * as library from "sap/ui/core/library"; } - } + }); - return hasAsyncInterface; + return hasAsyncImport ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { @@ -159,9 +179,14 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string if (metadata && ts.isPropertyDeclaration(metadata) && metadata.initializer && ts.isObjectLiteralExpression(metadata.initializer)) { metadata.initializer.properties.forEach((prop) => { - if (["interfaces", "\"interfaces\""].includes(prop.name?.getText() ?? "")) { + if (!prop.name) { + return; + } + const propText = getPropertyName(prop.name); + + if (propText === "interfaces") { classInterfaces = prop; - } else if (["manifest", "\"manifest\""].includes(prop.name?.getText() ?? "")) { + } else if (propText === "manifest") { componentManifest = prop; } }); @@ -171,8 +196,10 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { const hasAsyncInterfaceProp = classInterfaces.initializer - .elements.some((implementedInterface) => - implementedInterface.getText() === "\"sap.ui.core.IAsyncContentCreation\""); + .elements.some((implementedInterface) => { + return ts.isStringLiteral(implementedInterface) && + implementedInterface.text === "sap.ui.core.IAsyncContentCreation"; + }); hasAsyncInterface = hasAsyncInterfaceProp ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } @@ -193,8 +220,8 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string const manifestJson = extractPropsRecursive(componentManifest.initializer) ?? {}; let manifestSapui5Section: propsRecordValueType | propsRecordValueType[] | undefined; - if (instanceOfPropsRecord(manifestJson["\"sap.ui5\""])) { - manifestSapui5Section = manifestJson["\"sap.ui5\""].value; + if (instanceOfPropsRecord(manifestJson["sap.ui5"])) { + manifestSapui5Section = manifestJson["sap.ui5"].value; } if (instanceOfPropsRecord(manifestSapui5Section) && @@ -253,6 +280,14 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string }; } +function getPropertyName(node: ts.PropertyName): string { + if (ts.isStringLiteralLike(node) || ts.isNumericLiteral(node)) { + return node.text; + } else { + return node.getText(); + } +} + function extractPropsRecursive(node: ts.ObjectLiteralExpression) { const properties = Object.create(null) as propsRecord; @@ -261,7 +296,7 @@ function extractPropsRecursive(node: ts.ObjectLiteralExpression) { return; } - const key = prop.name.getText(); + const key = getPropertyName(prop.name); if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) { properties[key] = {value: true, node: prop.initializer}; } else if (prop.initializer.kind === ts.SyntaxKind.FalseKeyword) { @@ -279,12 +314,9 @@ function extractPropsRecursive(node: ts.ObjectLiteralExpression) { }).filter(($) => $) as propsRecordValueType[]; properties[key] = {value: resolvedValue, node: prop.initializer}; - } else if ( - (ts.isIdentifier(prop.initializer) || - ts.isNumericLiteral(prop.initializer) || - ts.isStringLiteral(prop.initializer)) && - - prop.initializer.getText()) { + } else if (ts.isStringLiteralLike(prop.initializer) || ts.isNumericLiteral(prop.initializer)) { + properties[key] = {value: prop.initializer.text, node: prop.initializer}; + } else if (ts.isIdentifier(prop.initializer) || ts.isPrivateIdentifier(prop.initializer)) { properties[key] = {value: prop.initializer.getText(), node: prop.initializer}; } else { // throw new Error("Unhandled property assignment"); From 608dd67bf746e8ee9b1b78409922069f8b87a81a Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 24 May 2024 11:17:19 +0200 Subject: [PATCH 83/90] refactor(asyncComponentFlags): Rename types, use boolean for async interface flag Since the async interface is either used or not, the information whether it is "not set" is redundant and the "parent property not set" information is not applicable. --- src/linter/ui5Types/asyncComponentFlags.ts | 95 +++++++++++----------- 1 file changed, 49 insertions(+), 46 deletions(-) diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 77a399085..2816a87e0 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -11,13 +11,18 @@ type propsRecord = Record; -enum AsyncInterfaceStatus {true, false, propNotSet, parentPropNotSet}; - -interface AsyncInterfaceFindType { - hasAsyncInterface: AsyncInterfaceStatus; +enum AsyncPropertyStatus { + true, // Property is set to true + false, // Property is set to false + propNotSet, // Property is not set + parentPropNotSet, // In the manifest, the parent object of the property is not set +}; + +interface AsyncFlags { + hasAsyncInterface: boolean; hasManifestDefinition: boolean; - routingAsyncFlag: AsyncInterfaceStatus; - rootViewAsyncFlag: AsyncInterfaceStatus; + routingAsyncFlag: AsyncPropertyStatus; + rootViewAsyncFlag: AsyncPropertyStatus; } export default function analyzeComponentJson({ @@ -53,13 +58,13 @@ export default function analyzeComponentJson({ } } -function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): AsyncInterfaceFindType { - const compareValues = (aProp: AsyncInterfaceStatus, bProp: AsyncInterfaceStatus): AsyncInterfaceStatus => { +function mergeResults(a: AsyncFlags, b: AsyncFlags): AsyncFlags { + const compareValues = (aProp: AsyncPropertyStatus, bProp: AsyncPropertyStatus): AsyncPropertyStatus => { const priorityCheck = [ - AsyncInterfaceStatus.parentPropNotSet, - AsyncInterfaceStatus.propNotSet, - AsyncInterfaceStatus.false, - AsyncInterfaceStatus.true, + AsyncPropertyStatus.parentPropNotSet, + AsyncPropertyStatus.propNotSet, + AsyncPropertyStatus.false, + AsyncPropertyStatus.true, ]; const aIndex = priorityCheck.indexOf(aProp); const bIndex = priorityCheck.indexOf(bProp); @@ -71,7 +76,7 @@ function mergeResults(a: AsyncInterfaceFindType, b: AsyncInterfaceFindType): Asy hasManifestDefinition: a.hasManifestDefinition || b.hasManifestDefinition, routingAsyncFlag: compareValues(a.routingAsyncFlag, b.routingAsyncFlag), rootViewAsyncFlag: compareValues(a.rootViewAsyncFlag, b.rootViewAsyncFlag), - hasAsyncInterface: compareValues(a.hasAsyncInterface, b.hasAsyncInterface), + hasAsyncInterface: a.hasAsyncInterface || b.hasAsyncInterface, }; } @@ -79,13 +84,13 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { classDefinition: ts.ClassDeclaration; manifestContent: string | undefined; checker: ts.TypeChecker; -}): AsyncInterfaceFindType | undefined { +}): AsyncFlags | undefined { const returnTypeTemplate = { - hasAsyncInterface: AsyncInterfaceStatus.parentPropNotSet, - routingAsyncFlag: AsyncInterfaceStatus.parentPropNotSet, - rootViewAsyncFlag: AsyncInterfaceStatus.parentPropNotSet, + hasAsyncInterface: false, + routingAsyncFlag: AsyncPropertyStatus.parentPropNotSet, + rootViewAsyncFlag: AsyncPropertyStatus.parentPropNotSet, hasManifestDefinition: false, - } as AsyncInterfaceFindType; + } as AsyncFlags; // Checks the interfaces and manifest const curClassAnalysis = classDefinition.members.reduce((acc, member) => { @@ -99,7 +104,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { const parentClassType = checker.getTypeAtLocation(parentClass); return parentClassType.symbol?.declarations?.flatMap((declaration) => { - let result = {...returnTypeTemplate} as AsyncInterfaceFindType; + let result = {...returnTypeTemplate} as AsyncFlags; // Continue down the heritage chain to search for // the async interface or manifest flags if (ts.isClassDeclaration(declaration)) { @@ -128,7 +133,7 @@ function isCoreImportDeclaration(statement: ts.Node): statement is ts.ImportDecl statement.moduleSpecifier.text === "sap/ui/core/library"; } -function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatus { +function doAsyncInterfaceChecks(importDeclaration: ts.Node): boolean { const sourceFile = importDeclaration.getSourceFile(); let coreLibImports: ts.ImportDeclaration[] | undefined; @@ -149,9 +154,8 @@ function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatu coreLibImports = sourceFile.statements.filter(isCoreImportDeclaration); } - // let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; if (!coreLibImports) { - return AsyncInterfaceStatus.propNotSet; + return false; } const hasAsyncImport = coreLibImports.some((importDecl) => { const importClause = importDecl.importClause; @@ -166,10 +170,11 @@ function doAsyncInterfaceChecks(importDeclaration: ts.Node): AsyncInterfaceStatu (namedImport) => namedImport.getText() === "IAsyncContentCreation"); } else { // Example: import * as library from "sap/ui/core/library"; + // TODO: This requires additional handling } }); - return hasAsyncImport ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + return hasAsyncImport; } function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string | undefined) { @@ -192,20 +197,18 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string }); } - let hasAsyncInterface = AsyncInterfaceStatus.propNotSet; + let hasAsyncInterface = false; if (classInterfaces && ts.isPropertyAssignment(classInterfaces) && classInterfaces.initializer && ts.isArrayLiteralExpression(classInterfaces.initializer)) { - const hasAsyncInterfaceProp = classInterfaces.initializer + hasAsyncInterface = classInterfaces.initializer .elements.some((implementedInterface) => { - return ts.isStringLiteral(implementedInterface) && + return ts.isStringLiteralLike(implementedInterface) && implementedInterface.text === "sap.ui.core.IAsyncContentCreation"; }); - - hasAsyncInterface = hasAsyncInterfaceProp ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; } - let rootViewAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; - let routingAsyncFlag: AsyncInterfaceStatus = AsyncInterfaceStatus.parentPropNotSet; + let rootViewAsyncFlag: AsyncPropertyStatus = AsyncPropertyStatus.parentPropNotSet; + let routingAsyncFlag: AsyncPropertyStatus = AsyncPropertyStatus.parentPropNotSet; let hasManifestDefinition = false; if (componentManifest && @@ -226,22 +229,22 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string if (instanceOfPropsRecord(manifestSapui5Section) && instanceOfPropsRecord(manifestSapui5Section?.rootView?.value)) { - rootViewAsyncFlag = AsyncInterfaceStatus.propNotSet; + rootViewAsyncFlag = AsyncPropertyStatus.propNotSet; if (typeof manifestSapui5Section?.rootView?.value.async?.value === "boolean") { const isRootViewAsync = manifestSapui5Section?.rootView?.value.async?.value; - rootViewAsyncFlag = isRootViewAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + rootViewAsyncFlag = isRootViewAsync ? AsyncPropertyStatus.true : AsyncPropertyStatus.false; } } if (instanceOfPropsRecord(manifestSapui5Section) && instanceOfPropsRecord(manifestSapui5Section?.routing?.value)) { - routingAsyncFlag = AsyncInterfaceStatus.propNotSet; + routingAsyncFlag = AsyncPropertyStatus.propNotSet; if (instanceOfPropsRecord(manifestSapui5Section?.routing?.value.config?.value) && typeof manifestSapui5Section?.routing?.value.config?.value.async?.value === "boolean") { const isRoutingAsync = manifestSapui5Section?.routing?.value.config?.value.async?.value; - routingAsyncFlag = isRoutingAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + routingAsyncFlag = isRoutingAsync ? AsyncPropertyStatus.true : AsyncPropertyStatus.false; } } } else { @@ -251,19 +254,19 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; if (rootView) { - rootViewAsyncFlag = AsyncInterfaceStatus.propNotSet; + rootViewAsyncFlag = AsyncPropertyStatus.propNotSet; // @ts-expect-error async is part of RootViewDefFlexEnabled and RootViewDef const isRootViewAsync = rootView.async as boolean | undefined; if (typeof isRootViewAsync === "boolean") { - rootViewAsyncFlag = isRootViewAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + rootViewAsyncFlag = isRootViewAsync ? AsyncPropertyStatus.true : AsyncPropertyStatus.false; } } if (routing) { - routingAsyncFlag = AsyncInterfaceStatus.propNotSet; + routingAsyncFlag = AsyncPropertyStatus.propNotSet; const isRoutingAsync = routing?.config?.async; if (typeof isRoutingAsync === "boolean") { - routingAsyncFlag = isRoutingAsync ? AsyncInterfaceStatus.true : AsyncInterfaceStatus.false; + routingAsyncFlag = isRoutingAsync ? AsyncPropertyStatus.true : AsyncPropertyStatus.false; } } @@ -328,7 +331,7 @@ function extractPropsRecursive(node: ts.ObjectLiteralExpression) { function reportResults({ analysisResult, reporter, classDesc, manifestContent, resourcePath, context, }: { - analysisResult: AsyncInterfaceFindType; + analysisResult: AsyncFlags; reporter: SourceFileReporter; context: LinterContext; classDesc: ts.ClassDeclaration; @@ -348,21 +351,21 @@ function reportResults({ }); } - if (hasAsyncInterface !== AsyncInterfaceStatus.true) { - if ([AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(rootViewAsyncFlag) || - [AsyncInterfaceStatus.propNotSet, AsyncInterfaceStatus.false].includes(routingAsyncFlag)) { + if (hasAsyncInterface !== true) { + if ([AsyncPropertyStatus.propNotSet, AsyncPropertyStatus.false].includes(rootViewAsyncFlag) || + [AsyncPropertyStatus.propNotSet, AsyncPropertyStatus.false].includes(routingAsyncFlag)) { let message = "Root View and Routing are not configured to load their modules asynchronously."; let messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest"; - if (AsyncInterfaceStatus.parentPropNotSet === rootViewAsyncFlag) { + if (AsyncPropertyStatus.parentPropNotSet === rootViewAsyncFlag) { // sap.ui5/rootView is not set at all, so skip it in the message message = "Routing is not configured to load its targets asynchronously."; messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + "\"sap.ui5/routing/config\" in the manifest."; - } else if (AsyncInterfaceStatus.parentPropNotSet === routingAsyncFlag) { + } else if (AsyncPropertyStatus.parentPropNotSet === routingAsyncFlag) { // sap.ui5/routing/config is not set at all, so skip it in the message message = "Root View is not configured to load its views asynchronously."; messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + @@ -391,7 +394,7 @@ function reportResults({ } }; - if (rootViewAsyncFlag === AsyncInterfaceStatus.true) { + if (rootViewAsyncFlag === AsyncPropertyStatus.true) { report("/sap.ui5/rootView/async", { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", @@ -400,7 +403,7 @@ function reportResults({ messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", }); } - if (routingAsyncFlag === AsyncInterfaceStatus.true) { + if (routingAsyncFlag === AsyncPropertyStatus.true) { report("/sap.ui5/routing/config/async", { severity: LintMessageSeverity.Warning, ruleId: "ui5-linter-no-sync-loading", From a71839796cd8a129642225a6423bc3b9562679de Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 24 May 2024 11:26:41 +0200 Subject: [PATCH 84/90] refactor(asyncComponentFlags): Simplify async flag merge logic Use enum value for implicit searching --- src/linter/ui5Types/asyncComponentFlags.ts | 32 ++++++++-------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 2816a87e0..b19020507 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -12,10 +12,10 @@ type propsRecord = Record; enum AsyncPropertyStatus { - true, // Property is set to true - false, // Property is set to false - propNotSet, // Property is not set parentPropNotSet, // In the manifest, the parent object of the property is not set + propNotSet, // Property is not set + false, // Property is set to false + true, // Property is set to true }; interface AsyncFlags { @@ -57,25 +57,15 @@ export default function analyzeComponentJson({ reportResults({analysisResult, context, reporter, resourcePath, classDesc, manifestContent}); } } +function getHighestPropertyStatus(aProp: AsyncPropertyStatus, bProp: AsyncPropertyStatus): AsyncPropertyStatus { + return aProp > bProp ? aProp : bProp; +}; -function mergeResults(a: AsyncFlags, b: AsyncFlags): AsyncFlags { - const compareValues = (aProp: AsyncPropertyStatus, bProp: AsyncPropertyStatus): AsyncPropertyStatus => { - const priorityCheck = [ - AsyncPropertyStatus.parentPropNotSet, - AsyncPropertyStatus.propNotSet, - AsyncPropertyStatus.false, - AsyncPropertyStatus.true, - ]; - const aIndex = priorityCheck.indexOf(aProp); - const bIndex = priorityCheck.indexOf(bProp); - - return (aIndex > bIndex) ? aProp : bProp; - }; - +function mergeAsyncFlags(a: AsyncFlags, b: AsyncFlags): AsyncFlags { return { hasManifestDefinition: a.hasManifestDefinition || b.hasManifestDefinition, - routingAsyncFlag: compareValues(a.routingAsyncFlag, b.routingAsyncFlag), - rootViewAsyncFlag: compareValues(a.rootViewAsyncFlag, b.rootViewAsyncFlag), + routingAsyncFlag: getHighestPropertyStatus(a.routingAsyncFlag, b.routingAsyncFlag), + rootViewAsyncFlag: getHighestPropertyStatus(a.rootViewAsyncFlag, b.rootViewAsyncFlag), hasAsyncInterface: a.hasAsyncInterface || b.hasAsyncInterface, }; } @@ -95,7 +85,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { // Checks the interfaces and manifest const curClassAnalysis = classDefinition.members.reduce((acc, member) => { const checkResult = doPropsCheck(member as ts.PropertyDeclaration, manifestContent); - return mergeResults(acc, checkResult); + return mergeAsyncFlags(acc, checkResult); }, {...returnTypeTemplate}); const heritageAnalysis = @@ -123,7 +113,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { }) ?? []; return [...heritageAnalysis, curClassAnalysis].reduce((acc, curAnalysis) => { - return mergeResults(acc ?? {...returnTypeTemplate}, curAnalysis ?? {...returnTypeTemplate}); + return mergeAsyncFlags(acc ?? {...returnTypeTemplate}, curAnalysis ?? {...returnTypeTemplate}); }); } From 992dee435e192e25c07d2bc6e39bb6a910913ae2 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 27 May 2024 09:41:36 +0200 Subject: [PATCH 85/90] test(AsyncComponentFlags): Move parent components into subdirs Document test fixtures --- src/linter/ui5Types/SourceFileLinter.ts | 3 + src/linter/ui5Types/TypeLinter.ts | 2 +- src/linter/ui5Types/asyncComponentFlags.ts | 12 +- .../Negative_01/Component.js | 2 + .../Negative_02/Component.js | 2 + .../Negative_03/Component.js | 2 + .../Negative_04/Component.js | 2 + .../Negative_05/Component.js | 7 +- .../Negative_05/ParentComponent.js | 9 - .../Negative_05/subdir/ParentComponent.js | 6 + .../Negative_06/Component.js | 3 +- .../Negative_06/ParentComponent.js | 9 - .../Negative_06/subdir/ParentComponent.js | 53 ++++++ .../Negative_07/Component.js | 1 + .../Negative_08/Component.js | 1 + .../Negative_09/Component.js | 10 - .../Negative_09/Component.ts | 9 + .../Negative_09/subdir/ParentComponent.ts | 6 + .../Negative_10/Component.js | 5 - .../Negative_10/Component.ts | 10 + .../Negative_10/ParentComponent.js | 10 - .../Negative_10/subdir/ParentComponent.ts | 6 + .../Negative_11/Component.ts | 7 - .../Negative_11/ParentComponent.ts | 4 - .../Positive_01/Component.js | 2 + .../Positive_02/Component.js | 2 + .../Positive_03/Component.js | 2 + .../Positive_04/Component.js | 2 + .../Positive_05/Component.js | 4 +- .../Positive_05/ParentComponent.js | 9 - .../Positive_05/manifest.json | 47 ----- .../Positive_05/subdir/ParentComponent.js | 18 ++ .../Positive_06/Component.js | 3 + .../Positive_07/Component.js | 2 + .../Positive_08/Component.js | 2 + .../Positive_09/Component.js | 11 +- .../Positive_09/ParentComponent.js | 9 - .../Positive_10/Component.js | 10 + .../manifest.json | 0 .../Positive_11/Component.ts | 9 + .../manifest.json | 0 .../AsyncComponentFlags/test-overview.md | 20 ++ test/lib/linter/_linterHelper.ts | 6 +- .../rules/snapshots/AsyncComponentFlags.ts.md | 179 +++++++----------- .../snapshots/AsyncComponentFlags.ts.snap | Bin 2047 -> 1763 bytes 45 files changed, 278 insertions(+), 240 deletions(-) delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/subdir/ParentComponent.js delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/subdir/ParentComponent.js delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.ts create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/subdir/ParentComponent.ts delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.ts delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/subdir/ParentComponent.ts delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/subdir/ParentComponent.js delete mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/Component.js rename test/fixtures/linter/rules/AsyncComponentFlags/{Negative_06 => Positive_10}/manifest.json (100%) create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/Component.ts rename test/fixtures/linter/rules/AsyncComponentFlags/{Negative_11 => Positive_11}/manifest.json (100%) create mode 100644 test/fixtures/linter/rules/AsyncComponentFlags/test-overview.md diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index bfe870646..025b8c172 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -183,6 +183,9 @@ export default class SourceFileLinter { // returned by a class constructor. // However, the OPA Matchers are a known exception where constructors do return a function. return; + } else if (exprNode.kind === ts.SyntaxKind.SuperKeyword) { + // Ignore super calls + return; } if (!ts.isPropertyAccessExpression(exprNode) && diff --git a/src/linter/ui5Types/TypeLinter.ts b/src/linter/ui5Types/TypeLinter.ts index db9e10e06..d2779d6d0 100644 --- a/src/linter/ui5Types/TypeLinter.ts +++ b/src/linter/ui5Types/TypeLinter.ts @@ -104,7 +104,7 @@ export default class TypeChecker { log.verbose(`Failed to get source map for ${sourceFile.fileName}`); } let manifestContent; - if (sourceFile.fileName.endsWith("/Component.js")) { + if (sourceFile.fileName.endsWith("/Component.js") || sourceFile.fileName.endsWith("/Component.ts")) { const res = await this.#workspace.byPath(path.dirname(sourceFile.fileName) + "/manifest.json"); if (res) { manifestContent = await res.getString(); diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index b19020507..5dfb2c43e 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -70,6 +70,9 @@ function mergeAsyncFlags(a: AsyncFlags, b: AsyncFlags): AsyncFlags { }; } +/** + * Search for the async interface in the class hierarchy +*/ function findAsyncInterface({classDefinition, manifestContent, checker}: { classDefinition: ts.ClassDeclaration; manifestContent: string | undefined; @@ -82,7 +85,7 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { hasManifestDefinition: false, } as AsyncFlags; - // Checks the interfaces and manifest + // Checks the interfaces and manifest of the class const curClassAnalysis = classDefinition.members.reduce((acc, member) => { const checkResult = doPropsCheck(member as ts.PropertyDeclaration, manifestContent); return mergeAsyncFlags(acc, checkResult); @@ -100,7 +103,8 @@ function findAsyncInterface({classDefinition, manifestContent, checker}: { if (ts.isClassDeclaration(declaration)) { result = findAsyncInterface({ classDefinition: declaration, - manifestContent, + // We are unable to dynamically search for a parent-component's manifest.json + manifestContent: undefined, checker, }) ?? result; } else if (ts.isInterfaceDeclaration(declaration)) { @@ -237,9 +241,9 @@ function doPropsCheck(metadata: ts.PropertyDeclaration, manifestContent: string routingAsyncFlag = isRoutingAsync ? AsyncPropertyStatus.true : AsyncPropertyStatus.false; } } - } else { + } else if (manifestContent) { const parsedManifestContent = - JSON.parse(manifestContent ?? "{}") as SAPJSONSchemaForWebApplicationManifestFile; + JSON.parse(manifestContent) as SAPJSONSchemaForWebApplicationManifestFile; const {rootView, routing} = parsedManifestContent["sap.ui5"] ?? {} as JSONSchemaForSAPUI5Namespace; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js index fc14feb52..922ef9db8 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_01/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// IAsyncContentCreation interface is implemented, no redundant async flags in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js index d34ea7e2d..e847e6806 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_02/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// Async flags are maintained in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js index 62cf1d6a3..4df637e91 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_03/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// IAsyncContentCreation interface is implemented, no redundant async flags in manifest sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js index fb85742d2..403ec1866 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_04/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// Async flags are maintained, no IAsyncContentCreation interface implemented sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js index 80ece1eae..079eb560a 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/Component.js @@ -1,6 +1,11 @@ -sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { +// Fixture description: +// Async flags are maintained in manifest.json. Inheriting from parent component. +sap.ui.define(["mycomp/subdir/ParentComponent"], function (ParentComponent) { "use strict"; return ParentComponent.extend("mycomp.Component", { + metadata: { + manifest: "json", + }, }); }); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js deleted file mode 100644 index 58668af47..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/ParentComponent.js +++ /dev/null @@ -1,9 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { - "use strict"; - - return UIComponent.extend("mycomp.ParentComponent", { - metadata: { - manifest: "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/subdir/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/subdir/ParentComponent.js new file mode 100644 index 000000000..01a5e3b18 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_05/subdir/ParentComponent.js @@ -0,0 +1,6 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.subdir.ParentComponent", { + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js index 34460fe40..2b70a5fa2 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/Component.js @@ -1,4 +1,5 @@ -sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { +// IAsyncContentCreation interface is implemented, no redundant async flags in inline manifest of parent component +sap.ui.define(["mycomp/subdir/ParentComponent"], function (ParentComponent) { "use strict"; return ParentComponent.extend("mycomp.Component", { diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js deleted file mode 100644 index 58668af47..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/ParentComponent.js +++ /dev/null @@ -1,9 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { - "use strict"; - - return UIComponent.extend("mycomp.ParentComponent", { - metadata: { - manifest: "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/subdir/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/subdir/ParentComponent.js new file mode 100644 index 000000000..37dd42ae3 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/subdir/ParentComponent.js @@ -0,0 +1,53 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.subdir.ParentComponent", { + metadata: { + manifest: { + _version: "1.12.0", + + "sap.app": { + id: "mycomp", + type: "application", + i18n: "i18n/i18n.properties", + title: "{{appTitle}}", + description: "{{appDescription}}", + applicationVersion: { + version: "1.0.0", + }, + }, + + "sap.ui5": { + rootView: { + viewName: "mycomp.view.App", + type: "XML", + id: "app", + }, + + routing: { + config: { + routerClass: "sap.m.routing.Router", + viewType: "XML", + viewPath: "mycomp.view", + controlId: "app", + controlAggregation: "pages", + }, + routes: [ + { + pattern: "", + name: "main", + target: "main", + }, + ], + targets: { + main: { + viewId: "main", + viewName: "Main", + }, + }, + }, + }, + }, + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js index 110f10e4a..596cd3fdf 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_07/Component.js @@ -1,3 +1,4 @@ +// Inheriting from sap/fe/core/AppComponent (implements IAsyncContentCreation interface), no redundant async flags in manifest sap.ui.define(["sap/fe/core/AppComponent"], function (AppComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js index f513569e3..2cdad8a9c 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_08/Component.js @@ -1,3 +1,4 @@ +// No rootView or router config and no IAsyncContentCreation interface implemented sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js deleted file mode 100644 index 021cd32da..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.js +++ /dev/null @@ -1,10 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/library"], function (UIComponent, coreLib) { - "use strict"; - - return UIComponent.extend("mycomp.Component", { - "metadata": { - "interfaces": [coreLib.IAsyncContentCreation], - "manifest": "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.ts new file mode 100644 index 000000000..c37a7c877 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/Component.ts @@ -0,0 +1,9 @@ +// Fixture description: +// TypeScript component which inherits from ParentComponent which implements IAsyncContentCreation interface +import ParentComponent from "mycomp/subdir/ParentComponent"; + +export default class Component extends ParentComponent { + static metadata = { + manifest: "json", + }; +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/subdir/ParentComponent.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/subdir/ParentComponent.ts new file mode 100644 index 000000000..c6825bbc6 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_09/subdir/ParentComponent.ts @@ -0,0 +1,6 @@ +import UIComponent from "sap/ui/core/UIComponent"; +import { IAsyncContentCreation } from "sap/ui/core/library"; + +export default class Component extends UIComponent implements IAsyncContentCreation { + __implements__sap_ui_core_IAsyncContentCreation: boolean; +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js deleted file mode 100644 index d239b16df..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.js +++ /dev/null @@ -1,5 +0,0 @@ -sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { - "use strict"; - - return ParentComponent.extend("mycomp.Component", {}); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.ts new file mode 100644 index 000000000..0a56f6c3d --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/Component.ts @@ -0,0 +1,10 @@ +// Fixture description: +// TypeScript component which inherits from ParentComponent which implements IAsyncContentCreation interface through metadata +import ParentComponent from "mycomp/subdir/ParentComponent"; +import * as library from "sap/ui/core/library"; // Unused core library import for code coverage purposes + +export default class Component extends ParentComponent { + static metadata = { + manifest: "json" + }; +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js deleted file mode 100644 index 9f2b206b2..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/ParentComponent.js +++ /dev/null @@ -1,10 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/library"], function (UIComponent, coreLib) { - "use strict"; - - return UIComponent.extend("mycomp.ParentComponent", { - metadata: { - interfaces: [coreLib.IAsyncContentCreation], - manifest: "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/subdir/ParentComponent.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/subdir/ParentComponent.ts new file mode 100644 index 000000000..991baefb8 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_10/subdir/ParentComponent.ts @@ -0,0 +1,6 @@ +import UIComponent from "sap/ui/core/UIComponent"; +export default class Component extends UIComponent { + static metadata = { + interfaces: ["sap.ui.core.IAsyncContentCreation"], + } +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts deleted file mode 100644 index 4911f0251..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/Component.ts +++ /dev/null @@ -1,7 +0,0 @@ -import ParentComponent from "mycomp/ParentComponent"; - -export default class Component extends ParentComponent { - static metadata = { - manifest: "json", - }; -} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts deleted file mode 100644 index 10ef4a980..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/ParentComponent.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { IAsyncContentCreation } from "sap/ui/core/library"; - -export default class Component implements IAsyncContentCreation { -} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js index d34ea7e2d..d38b6a97c 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_01/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// No IAsyncContentCreation interface is implemented, no async flags in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js index 9c77822b8..daef7eed1 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_02/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// IAsyncContentCreation interface is implemented, redundant async flags in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js index fbf972b0b..411d0c4e0 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_03/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// No IAsyncContentCreation interface, missing async flags in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js index 4396d0ef5..eff7b1afa 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_04/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// IAsyncContentCreation interface is implemented, redundant async flags in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js index 34460fe40..a6474f7b1 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/Component.js @@ -1,4 +1,6 @@ -sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { +// Fixture description: +// IAsyncContentCreation interface is implemented, redundant async flags in manifest of parent component +sap.ui.define(["mycomp/subdir/ParentComponent"], function (ParentComponent) { "use strict"; return ParentComponent.extend("mycomp.Component", { diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js deleted file mode 100644 index 58668af47..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/ParentComponent.js +++ /dev/null @@ -1,9 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { - "use strict"; - - return UIComponent.extend("mycomp.ParentComponent", { - metadata: { - manifest: "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json deleted file mode 100644 index 0e4163721..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/manifest.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "_version": "1.12.0", - - "sap.app": { - "id": "mycomp", - "type": "application", - "i18n": "i18n/i18n.properties", - "title": "{{appTitle}}", - "description": "{{appDescription}}", - "applicationVersion": { - "version": "1.0.0" - } - }, - - "sap.ui5": { - "rootView": { - "viewName": "mycomp.view.App", - "type": "XML", - "id": "app", - "async": true - }, - - "routing": { - "config": { - "routerClass": "sap.m.routing.Router", - "viewType": "XML", - "viewPath": "mycomp.view", - "controlId": "app", - "controlAggregation": "pages", - "async": true - }, - "routes": [ - { - "pattern": "", - "name": "main", - "target": "main" - } - ], - "targets": { - "main": { - "viewId": "main", - "viewName": "Main" - } - } - } - } -} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/subdir/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/subdir/ParentComponent.js new file mode 100644 index 000000000..7f65dca07 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_05/subdir/ParentComponent.js @@ -0,0 +1,18 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { + "use strict"; + + return UIComponent.extend("mycomp.subdir.ParentComponent", { + metadata: { + manifest: { + "sap.ui5": { + rootView: { + viewName: "mycomp.view.App", + type: "XML", + id: "app", + async: true + }, + } + } + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js index c3e6750a9..8d7041b49 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_06/Component.js @@ -1,3 +1,6 @@ +// Fixture description: +// IAsyncContentCreation interface is implemented, redundant async flag (rootView only) in manifest.json +// No manifest: "json" configuration in metadata sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js index 65390c90e..22139a002 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_07/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// No IAsyncContentCreation interface is implemented, no async flag (rootView only) in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js index 65390c90e..1e781a422 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_08/Component.js @@ -1,3 +1,5 @@ +// Fixture description: +// No IAsyncContentCreation interface is implemented, no async flag (routing only) in manifest.json sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { "use strict"; diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js index d239b16df..72aa31bbc 100644 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/Component.js @@ -1,5 +1,12 @@ -sap.ui.define(["mycomp/ParentComponent"], function (ParentComponent) { +// IAsyncContentCreation interface is implemented via sap.ui.core.library property +// which is a bad practice (see https://github.com/SAP/openui5/issues/3895) and therefore ignored +sap.ui.define(["sap/ui/core/UIComponent", "sap/ui/core/library"], function (UIComponent, coreLib) { "use strict"; - return ParentComponent.extend("mycomp.Component", {}); + return UIComponent.extend("mycomp.Component", { + "metadata": { + "interfaces": [coreLib.IAsyncContentCreation], + "manifest": "json", + }, + }); }); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js deleted file mode 100644 index 58668af47..000000000 --- a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_09/ParentComponent.js +++ /dev/null @@ -1,9 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { - "use strict"; - - return UIComponent.extend("mycomp.ParentComponent", { - metadata: { - manifest: "json", - }, - }); -}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/Component.js b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/Component.js new file mode 100644 index 000000000..4e57f9910 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/Component.js @@ -0,0 +1,10 @@ +// Component which does not inherit from UIComponent (this should actually not be analyzed) +sap.ui.define(["sap/ui/core/Component"], function (Component) { + "use strict"; + + return Component.extend("mycomp.Component", { + "metadata": { + "manifest": "json", + }, + }); +}); diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/manifest.json similarity index 100% rename from test/fixtures/linter/rules/AsyncComponentFlags/Negative_06/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_10/manifest.json diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/Component.ts b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/Component.ts new file mode 100644 index 000000000..ee83207c1 --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/Component.ts @@ -0,0 +1,9 @@ +// Fixture description: +// TypeScript component which does not implement IAsyncContentCreation interface, no async flags in manifest.json +import UIComponent from "sap/ui/core/UIComponent"; + +export default class Component extends UIComponent { + constructor() { + super("my.comp.Component"); + } +} diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json b/test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/manifest.json similarity index 100% rename from test/fixtures/linter/rules/AsyncComponentFlags/Negative_11/manifest.json rename to test/fixtures/linter/rules/AsyncComponentFlags/Positive_11/manifest.json diff --git a/test/fixtures/linter/rules/AsyncComponentFlags/test-overview.md b/test/fixtures/linter/rules/AsyncComponentFlags/test-overview.md new file mode 100644 index 000000000..504685b7f --- /dev/null +++ b/test/fixtures/linter/rules/AsyncComponentFlags/test-overview.md @@ -0,0 +1,20 @@ +## Test Variants + +### IAsyncContentCreation Interface + +Implemented either directly by the Component, by the Parent Component or not at all. + +Can be implemented by defining the string `sap.ui.core.IAsyncContentCreation` in the "interface" array of the component metadata, +or by using the IAsyncContentCreation property of the `sap/ui/core/library` module. The latter is discouraged as it does not work +in TypeScript (see also https://github.com/SAP/openui5/issues/3895), hence it is currently not detected. + +In case of TypeScript files, it can also be define using the `implements` keyword. + +### Async Manifest Flags + +There are two relevant flags in the component manifest. The manifest can either be a separate `manifest.json` file or defined inline in the component metadata. + +The first flag is `"sap.ui5".rootView.async`, which is only evaluated if `"sap.ui5".rootView` is defined. If this configuration object is not provided on a Component, a parent's + +The second flag is `"sap.ui5".routing.config.async`, which is only evaluated if `"sap.ui5".routing` is defined. + diff --git a/test/lib/linter/_linterHelper.ts b/test/lib/linter/_linterHelper.ts index 724a40fea..619635333 100644 --- a/test/lib/linter/_linterHelper.ts +++ b/test/lib/linter/_linterHelper.ts @@ -64,7 +64,11 @@ export function assertExpectedLintResults( // Helper function to create linting tests for all files in a directory export function createTestsForFixtures(fixturesPath: string) { try { - const testFiles = readdirSync(fixturesPath); + const testFiles = readdirSync(fixturesPath, {withFileTypes: true}).filter((dirEntries) => { + return dirEntries.isFile(); + }).map((dirEntries) => { + return dirEntries.name; + }); if (!testFiles.length) { throw new Error(`Failed to find any fixtures in directory ${fixturesPath}`); } diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index c573268d7..ede9a7591 100644 --- a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -69,14 +69,6 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'ParentComponent.js', - messages: [], - warningCount: 0, - }, { coverageInfo: [], errorCount: 0, @@ -92,14 +84,6 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'ParentComponent.js', - messages: [], - warningCount: 0, - }, { coverageInfo: [], errorCount: 0, @@ -145,72 +129,21 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', - severity: 2, - }, - ], - warningCount: 0, - }, - ] - -## General: Negative_10 - -> Snapshot 1 - - [ - { - coverageInfo: [], - errorCount: 1, - fatalErrorCount: 0, - filePath: 'Component.js', - messages: [ - { - column: 9, - fatal: undefined, - line: 4, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', - severity: 2, - }, - ], - warningCount: 0, - }, { coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'ParentComponent.js', + filePath: 'Component.ts', messages: [], warningCount: 0, }, ] -## General: Negative_11 +## General: Negative_10 > Snapshot 1 [ - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'ParentComponent.ts', - messages: [], - warningCount: 0, - }, { coverageInfo: [], errorCount: 0, @@ -235,7 +168,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: 'Root View and Routing are not configured to load their modules asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', ruleId: 'ui5-linter-no-sync-loading', @@ -302,7 +235,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: 'Root View and Routing are not configured to load their modules asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', ruleId: 'ui5-linter-no-sync-loading', @@ -327,7 +260,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', @@ -336,7 +269,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', ruleId: 'ui5-linter-no-sync-loading', @@ -356,44 +289,19 @@ Generated by [AVA](https://avajs.dev). coverageInfo: [], errorCount: 0, fatalErrorCount: 0, - filePath: 'manifest.json', + filePath: 'Component.js', messages: [ { - column: 12, - line: 19, + column: 9, + fatal: undefined, + line: 6, message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', - pos: 341, - ruleId: 'ui5-linter-no-sync-loading', - severity: 1, - }, - { - column: 16, - line: 29, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', - messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', - pos: 551, ruleId: 'ui5-linter-no-sync-loading', severity: 1, }, ], - warningCount: 2, - }, - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'ParentComponent.js', - messages: [], - warningCount: 0, - }, - { - coverageInfo: [], - errorCount: 0, - fatalErrorCount: 0, - filePath: 'Component.js', - messages: [], - warningCount: 0, + warningCount: 1, }, ] @@ -429,7 +337,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 7, message: 'Include a manifest section into the Component.js', messageDetails: 'manifest.json will be loaded and used, but is not defined in Component\'s metadata section', ruleId: 'ui5-linter-add-manifest', @@ -454,7 +362,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: 'Root View is not configured to load its views asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/rootView" in the manifest.', ruleId: 'ui5-linter-no-sync-loading', @@ -479,7 +387,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: 'Routing is not configured to load its targets asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', ruleId: 'ui5-linter-no-sync-loading', @@ -504,7 +412,7 @@ Generated by [AVA](https://avajs.dev). { column: 9, fatal: undefined, - line: 4, + line: 6, message: 'Root View and Routing are not configured to load their modules asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', ruleId: 'ui5-linter-no-sync-loading', @@ -513,12 +421,63 @@ Generated by [AVA](https://avajs.dev). ], warningCount: 0, }, + ] + +## General: Positive_10 + +> Snapshot 1 + + [ { coverageInfo: [], - errorCount: 0, + errorCount: 1, fatalErrorCount: 0, - filePath: 'ParentComponent.js', - messages: [], + filePath: 'Component.js', + messages: [ + { + column: 9, + fatal: undefined, + line: 5, + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], warningCount: 0, }, ] + +## General: Positive_11 + +> Snapshot 1 + + [ + { + coverageInfo: [], + errorCount: 1, + fatalErrorCount: 0, + filePath: 'Component.ts', + messages: [ + { + column: 1, + fatal: undefined, + line: 5, + message: 'Include a manifest section into the Component.js', + messageDetails: 'manifest.json will be loaded and used, but is not defined in Component\'s metadata section', + ruleId: 'ui5-linter-add-manifest', + severity: 1, + }, + { + column: 1, + fatal: undefined, + line: 5, + message: 'Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', + ruleId: 'ui5-linter-no-sync-loading', + severity: 2, + }, + ], + warningCount: 1, + }, + ] diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap index 7fd583622ba14925bf8816fc3b79b4293490cf24..c82076e60bcd4e9549162c668ca2a52fd2db4422 100644 GIT binary patch literal 1763 zcmV<91|0c8RzVmQ2<00000000B+n_p-gMI6V!Gjn@){hQPZVxcg!LQGBWa%ujxs94fcqO~o7 ziY`9oetxvk+Qn}BZHVj?q`^mEm5qLi&N@y2=UI1%Jcn#6EIgUOhAtMS=u z4$I7>w1ur=6K-xq<0T`CW`yhNY2o_1SvjpcwrQu!uM{nd9V?4nd0VKYt%_#7fo3hI z+2%mAmeZ^+(5&S&>kl+*In4$F&00>g!9cT?(`+cvtmQP@5@=RKGquz-OY{VqwTNbW zrEAXVgM>CNs%94fTmjHdfKBt&?9qBP^M=wGIGT+SjnHG)J3c`$r+Ot3euESu9Q~RA zR|r5Tu$}^2C~%enA2EQ1d{NeJigLs^@NiOE*^FI?;WA&VmWyHTD6-1e7P3rR6wV9# z+9HK86_0n1N~!o`rkLisZSYZThx+AzP6;Db#Wu~)^Fu0Q3lDfgwxG)`_kw(@M zF4x@|J2~!1TV`ErCg!`^>cZ8w3#FTuTX>sZ!#-E=Z6&AjT~ar^3*S4g)TFyL9?zQn zF;}0AC1oa_h$VV^;v3^iPMXR1z~I2xz~+IzzJcVHKA{_WVrcVNqBk+55B2s9CI&lW zd?YhziHxun_qxcMv7~fFY$SKZVQDL2t6@jz%9J)YZ6%zPo)p})dFd46(&4U9`CH^E zOHaEzB^|yY-)Dc^$psE~mp3!YHC0yl~*~waB#3&xF%bNY& zR&Gq)w(RyU-EHM#<9|L}F(n*R%@mZTRghA_ri-LYkivQZ3;=kj7FK9((m#?vaRnjI zd4EZcFqZ&)2;c_*VFGj!-~a(s4Z=i8nmay5QtRc=oo=H~F@1M(*YM?y4qo*-sSsodQ>BHSCsm60Opbx4;b)N2>2%i+^qqlT6JkbU2Yc1DU2NKN+&>!kBW?(5;>gRprRj&Med~> znW;v;%E^I<+Q_b&B=ku$UbBl%-&okB%nu+$clgVdMI$tshurN|cXL4XRX)p-{#x3nT{l-xnJ+APtlq>l=F7T702`dGa5L2g||`XdEg z2E1J(Uj)Dpp8YxYzJ&j6MU(jEf+kN9d+C|PFV<-ilakwdcgdN=AJ>0ZHQ?wu#D6cq zA&&Sv00Y7dRcz#0y0+)7;@RUptVr8q3^>7n^9;DmfTu%1R0HnOfG2AE#fLTEhz6Y2 zfQuUNr3Q3{fw#iIw_)Gu%NEfuUK;>;@vXysP4$cG&CUK^{ccguh@G^uhT!_F9NZPj zqK_hTLX|)G^AT%*83OsVX<2+s~EA9RdkP;xJKBQ;?QUatTDttLb`?L8- z*}a62Qus#EM59&+*>M8AMu0cxx54Dx>;{uxZfr2=qChVN_ENy2zzY=k;`;C73^-PM zgULAtyvKk~8SpCumWO~tA>fn-eD;4gnD`}GEJ6jI=6qe{Mkx^Fh}$Md{0Cz_PukK+ F002~0R!0B; literal 2047 zcmV?;n-^4Ck`h*% zYzRbYK`FjsVQXZ&*)Wnc$I861(0 z^sM4R^O&5s0((h5Ha=ndj%l*Y%AkrBjJgn`&5 z#3KUUCsc&KU2Ms@OVYFE<&0Bs5yR{dO1*5e^gP!)0r zi}JV?EHv6Y;{~v|s7bLQ{{@CF%Rty!0d0Y+1HE$9Cpdx0GIGJ9U-qR+ni_ zWgRfvlVCP*nC(q48#v4+6U+tk4H0EU3w0v;2v5(8mcq@EXWQNRxbToaH|U{Zl&O5|0&4f>BO{YC$-8_vREV!Pzvs&j=)~gyTTQ$ms&O@U`)U%0YSW$ z{hEMp3izIYUkOkYm{MRis%4Ef>(KN z*u!zxx7%i0lRZ(gCrW&5;$v^k$KIrr7KZ^+^LN6>u5(ZHoPcm4y(%DFMydkiHhTwSft+{0>p=BA%g;b|3KRN;yWk8AKB4L+d5iJ09{TBJQ4KBL2V9WLomFyNmC zY)iqBRP3(4Gx2ZfK<;;SCU@l-Mq~MJw3z^X)2=h8%vZ>+c>-k26SCwk$qJp_WW^{c z)_Jesxus6b*V;J<8Bf_AorJY$XJf0_73qt*=vF(RDGx{G%57t4u@1OLI>3ET4BTJo z3*4)H;DCZYs`L!>4sN-{d9Ot2CrUq2`iau-R_V7mj%W<`KMCG7rSwe5cF8EAjEqsT z&kA_17BuWgD^*4MvZyQ4zlw$;eL#VUT2knY0$&P~L@K#EsG-by!Upm-ei>;X+Q|R^NTd>F0eOR=Yg>+ue<= zIa@WXZ8Q<`fYzgE+7S(oYVZlI7tyrUWkVgxwzSqfb6TAeE@%zS^E(axsDY+~sl!zr zP8qOdz$-?q=6T(KHw<{&fZ-HeNx^Iy&ZOambPuC&I}%-U`vWp3lPKK(iLU8;6t2bP z7vsN!m>g?&V9?ok$+0hYnH&>M!+K@ICC7f+{itHXlwoG<-`yV;6bdRBDjghtBkVI$ zO_4R8XVrS#^Xv@`c20#$DqL0Ja~h;|_@EA-jL(xjp~F);T+rdN4!_W0mjN#s@Y|?^ z-;{XhjZN15_0YYFl8?_gxnemlO{)Qi>C0R_e(Y9&TD|bs1JJHu zUkN9deVN~F&Xt33c7*}?ye!y`%&&@7kNRdw23F{!>b>d=!uy**u=4q_HdE|Y++~Za zaq7R4q}4zstjuUJIs%UWqIJvLa dW70|P>m~Q~k`qSB38S`r{Xb7(1Uwc}002l&@)rOA From f4be3cba3800cb46b7da2c8127faf93e32ad328b Mon Sep 17 00:00:00 2001 From: Yavor Ivanov Date: Tue, 28 May 2024 14:49:02 +0300 Subject: [PATCH 86/90] fix: Skip depcheck for fake modules in testing --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8ce3f8795..15eb006d6 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "check-licenses": "licensee --errors-only", "cleanup": "rimraf lib coverage", "coverage": "nyc ava --node-arguments=\"--experimental-loader=@istanbuljs/esm-loader-hook\"", - "depcheck": "depcheck --ignores @commitlint/config-conventional,@istanbuljs/esm-loader-hook,@sapui5/types,@ui5/logger,ava,rimraf,sap,tsx,json-source-map,he,@types/he", + "depcheck": "depcheck --ignores @commitlint/config-conventional,@istanbuljs/esm-loader-hook,@sapui5/types,@ui5/logger,ava,rimraf,sap,tsx,json-source-map,he,@types/he,mycomp", "hooks:pre-push": "npm run lint:commit", "lint": "eslint .", "lint:commit": "commitlint -e", From 85fda5015dcff26ed6ac3d45e596a37ee564ead7 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 28 May 2024 14:36:42 +0200 Subject: [PATCH 87/90] refactor: Improve file path handling --- src/linter/ui5Types/SourceFileLinter.ts | 9 ++++++--- src/linter/ui5Types/asyncComponentFlags.ts | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/linter/ui5Types/SourceFileLinter.ts b/src/linter/ui5Types/SourceFileLinter.ts index 025b8c172..a702f4e08 100644 --- a/src/linter/ui5Types/SourceFileLinter.ts +++ b/src/linter/ui5Types/SourceFileLinter.ts @@ -1,4 +1,5 @@ import ts, {Identifier} from "typescript"; +import path from "node:path/posix"; import SourceFileReporter from "./SourceFileReporter.js"; import LinterContext, {ResourcePath, CoverageCategory, LintMessageSeverity} from "../LinterContext.js"; import analyzeComponentJson from "./asyncComponentFlags.js"; @@ -18,6 +19,8 @@ export default class SourceFileLinter { #reportCoverage: boolean; #messageDetails: boolean; #manifestContent: string | undefined; + #fileName: string; + #isComponent: boolean; constructor( context: LinterContext, resourcePath: ResourcePath, sourceFile: ts.SourceFile, sourceMap: string | undefined, @@ -33,6 +36,8 @@ export default class SourceFileLinter { this.#reportCoverage = reportCoverage; this.#messageDetails = messageDetails; this.#manifestContent = manifestContent; + this.#fileName = path.basename(resourcePath); + this.#isComponent = this.#fileName === "Component.js" || this.#fileName === "Component.ts"; } // eslint-disable-next-line @typescript-eslint/require-await @@ -70,9 +75,7 @@ export default class SourceFileLinter { node as (ts.PropertyAccessExpression | ts.ElementAccessExpression)); // Check for deprecation } else if (node.kind === ts.SyntaxKind.ImportDeclaration) { this.analyzeImportDeclaration(node as ts.ImportDeclaration); // Check for deprecation - } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments && - ts.isSourceFile(this.#sourceFile) && - (this.#sourceFile.fileName.endsWith("/Component.js") || this.#sourceFile.fileName.endsWith("/Component.ts"))) { + } else if (node.kind === ts.SyntaxKind.ExpressionWithTypeArguments && this.#isComponent) { analyzeComponentJson({ node: node as ts.ExpressionWithTypeArguments, manifestContent: this.#manifestContent, diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 5dfb2c43e..9593cbef9 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -1,4 +1,5 @@ import ts from "typescript"; +import path from "node:path/posix"; import SourceFileReporter from "./SourceFileReporter.js"; import type {JSONSchemaForSAPUI5Namespace, SAPJSONSchemaForWebApplicationManifestFile} from "../../manifest.js"; import LinterContext, {LintMessage, LintMessageSeverity} from "../LinterContext.js"; @@ -381,8 +382,9 @@ function reportResults({ if (manifestContent) { // If the manifest.json is present, then we need to redirect the message pointers to it const {key: posInfo} = pointers[pointerKey]; + const fileName = path.basename(resourcePath); context.addLintingMessage( - resourcePath.replace("Component.js", "manifest.json"), {...message, ...posInfo}); + resourcePath.replace(fileName, "manifest.json"), {...message, ...posInfo}); } else { reporter.addMessage({...message, ...{node: classDesc}}); } From 7790b4a4aa120468ceca26d88b84baaa005c4868 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 28 May 2024 15:14:36 +0200 Subject: [PATCH 88/90] refactor: Update message texts --- src/linter/ui5Types/asyncComponentFlags.ts | 54 +++++++------ .../rules/snapshots/AsyncComponentFlags.ts.md | 74 +++++++++--------- .../snapshots/AsyncComponentFlags.ts.snap | Bin 1763 -> 1902 bytes 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 9593cbef9..8555b7d03 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -334,44 +334,47 @@ function reportResults({ resourcePath: string; }) { const {hasAsyncInterface, routingAsyncFlag, rootViewAsyncFlag, hasManifestDefinition} = analysisResult; + const fileName = path.basename(resourcePath); if (!hasManifestDefinition && !!manifestContent) { reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-add-manifest", - message: "Include a manifest section into the Component.js", - messageDetails: "manifest.json will be loaded and used, " + - "but is not defined in Component's metadata section", + ruleId: "ui5-linter-async-component-flags", + message: `Component does not specify that it uses the descriptor via the manifest.json file`, + messageDetails: + `A manifest.json has been found in the same directory as the component. Although it will be used at ` + + `runtime automatically, this should still be expressed in the ` + + `{@link topic:0187ea5e2eff4166b0453b9dcc8fc64f metadata of the component class}.`, }); } if (hasAsyncInterface !== true) { if ([AsyncPropertyStatus.propNotSet, AsyncPropertyStatus.false].includes(rootViewAsyncFlag) || [AsyncPropertyStatus.propNotSet, AsyncPropertyStatus.false].includes(routingAsyncFlag)) { - let message = "Root View and Routing are not configured to load their modules asynchronously."; - let messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for " + - "\"sap.ui5/routing/config\" and \"sap.ui5/rootView\" in the manifest"; + let message = `Component Root View and Routing are not configured to load their modules asynchronously.`; + let messageDetails = `{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. ` + + `Implement sap.ui.core.IAsyncContentCreation interface in ${fileName} or set the "async" flags for ` + + `"sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.`; if (AsyncPropertyStatus.parentPropNotSet === rootViewAsyncFlag) { // sap.ui5/rootView is not set at all, so skip it in the message - message = "Routing is not configured to load its targets asynchronously."; - messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + - "\"sap.ui5/routing/config\" in the manifest."; + message = `Routing is not configured to load its targets asynchronously.`; + messageDetails = `{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. ` + + `Implement sap.ui.core.IAsyncContentCreation interface in ${fileName} or set the "async" flag for ` + + `"sap.ui5/routing/config" in the component manifest.`; } else if (AsyncPropertyStatus.parentPropNotSet === routingAsyncFlag) { // sap.ui5/routing/config is not set at all, so skip it in the message - message = "Root View is not configured to load its views asynchronously."; - messageDetails = "{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. " + - "Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for " + - "\"sap.ui5/rootView\" in the manifest."; + message = `Root View is not configured to load its views asynchronously.`; + messageDetails = `{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. ` + + `Implement sap.ui.core.IAsyncContentCreation interface in ${fileName} or set the "async" flag for ` + + `"sap.ui5/rootView" in the component manifest.`; } reporter.addMessage({ node: classDesc, severity: LintMessageSeverity.Error, - ruleId: "ui5-linter-no-sync-loading", + ruleId: "ui5-linter-async-component-flags", message, messageDetails, }); @@ -382,7 +385,6 @@ function reportResults({ if (manifestContent) { // If the manifest.json is present, then we need to redirect the message pointers to it const {key: posInfo} = pointers[pointerKey]; - const fileName = path.basename(resourcePath); context.addLintingMessage( resourcePath.replace(fileName, "manifest.json"), {...message, ...posInfo}); } else { @@ -393,19 +395,19 @@ function reportResults({ if (rootViewAsyncFlag === AsyncPropertyStatus.true) { report("/sap.ui5/rootView/async", { severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-no-sync-loading", - message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + - "Remove the async flag for \"sap.ui5/rootView\" from the manifest", - messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", + ruleId: "ui5-linter-async-component-flags", + message: `Component implements the sap.ui.core.IAsyncContentCreation interface. ` + + `The redundant "async" flag for "sap.ui5/rootView" should be removed from the component manifest`, + messageDetails: `{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}`, }); } if (routingAsyncFlag === AsyncPropertyStatus.true) { report("/sap.ui5/routing/config/async", { severity: LintMessageSeverity.Warning, - ruleId: "ui5-linter-no-sync-loading", - message: "'sap.ui.core.IAsyncContentCreation' interface is implemented for Component.js. " + - "Remove the async flag for \"sap.ui5/routing/config\" from the manifest", - messageDetails: "{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}", + ruleId: "ui5-linter-async-component-flags", + message: `Component implements the sap.ui.core.IAsyncContentCreation interface. ` + + `The redundant "async" flag for "sap.ui5/routing/config" should be removed from the component manifest`, + messageDetails: `{@link sap.ui.core.IAsyncContentCreation sap.ui.core.IAsyncContentCreation}`, }); } } diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index ede9a7591..5a31a4775 100644 --- a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -169,9 +169,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', + message: 'Component Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -193,19 +193,19 @@ Generated by [AVA](https://avajs.dev). { column: 12, line: 18, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/rootView" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', pos: 325, - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, { column: 16, line: 29, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/routing/config" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', pos: 551, - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, ], @@ -236,9 +236,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', + message: 'Component Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -261,18 +261,18 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/rootView" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, { column: 9, fatal: undefined, line: 6, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/routing/config" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/routing/config" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, ], @@ -295,9 +295,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/rootView" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, ], @@ -319,10 +319,10 @@ Generated by [AVA](https://avajs.dev). { column: 12, line: 19, - message: '\'sap.ui.core.IAsyncContentCreation\' interface is implemented for Component.js. Remove the async flag for "sap.ui5/rootView" from the manifest', + message: 'Component implements the sap.ui.core.IAsyncContentCreation interface. The redundant "async" flag for "sap.ui5/rootView" should be removed from the component manifest', messageDetails: 'sap.ui.core.IAsyncContentCreation (https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation)', pos: 341, - ruleId: 'ui5-linter-no-sync-loading', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, ], @@ -338,9 +338,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 7, - message: 'Include a manifest section into the Component.js', - messageDetails: 'manifest.json will be loaded and used, but is not defined in Component\'s metadata section', - ruleId: 'ui5-linter-add-manifest', + message: 'Component does not specify that it uses the descriptor via the manifest.json file', + messageDetails: 'A manifest.json has been found in the same directory as the component. Although it will be used at runtime automatically, this should still be expressed in the metadata of the component class (https://ui5.sap.com/1.120/#/topic/0187ea5e2eff4166b0453b9dcc8fc64f).', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, ], @@ -364,8 +364,8 @@ Generated by [AVA](https://avajs.dev). fatal: undefined, line: 6, message: 'Root View is not configured to load its views asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/rootView" in the manifest.', - ruleId: 'ui5-linter-no-sync-loading', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flag for "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -389,8 +389,8 @@ Generated by [AVA](https://avajs.dev). fatal: undefined, line: 6, message: 'Routing is not configured to load its targets asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flag for "sap.ui5/routing/config" in the manifest.', - ruleId: 'ui5-linter-no-sync-loading', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flag for "sap.ui5/routing/config" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -413,9 +413,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', + message: 'Component Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -438,9 +438,9 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 5, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', + message: 'Component Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], @@ -463,18 +463,18 @@ Generated by [AVA](https://avajs.dev). column: 1, fatal: undefined, line: 5, - message: 'Include a manifest section into the Component.js', - messageDetails: 'manifest.json will be loaded and used, but is not defined in Component\'s metadata section', - ruleId: 'ui5-linter-add-manifest', + message: 'Component does not specify that it uses the descriptor via the manifest.json file', + messageDetails: 'A manifest.json has been found in the same directory as the component. Although it will be used at runtime automatically, this should still be expressed in the metadata of the component class (https://ui5.sap.com/1.120/#/topic/0187ea5e2eff4166b0453b9dcc8fc64f).', + ruleId: 'ui5-linter-async-component-flags', severity: 1, }, { column: 1, fatal: undefined, line: 5, - message: 'Root View and Routing are not configured to load their modules asynchronously.', - messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set async flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the manifest', - ruleId: 'ui5-linter-no-sync-loading', + message: 'Component Root View and Routing are not configured to load their modules asynchronously.', + messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.ts or set the "async" flags for "sap.ui5/routing/config" and "sap.ui5/rootView" in the component manifest.', + ruleId: 'ui5-linter-async-component-flags', severity: 2, }, ], diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap index c82076e60bcd4e9549162c668ca2a52fd2db4422..fdb93843c49bb7dc9c9e8597f812a8fbd2ea8347 100644 GIT binary patch literal 1902 zcmV-!2a)(eRzVmHPkwTGRYrqzn|HO zN0WIfG#`ry00000000B+n_r9@M;*t%GrMa$P13s%ka(#yI#6k7VxKQ}zDw02qNGBh ze-f&;qE#iB+nu#1UGG>svv)lq9;))Mty&?PR-huJv_c5cf?D;lRfP~jqE*EMF9`7f zRbNU#AXOlEfvo@Kyz$u==bW>ny_d5+p4pk-@3)`dZ@xP|@2>{ReN;dHk}%Q)!hAu5 zBI3bq>|RmjMy`pk%$KDOc|+Hf(T|_^JZ|_ygJ4Un`Ts~3$1xo=+rR#)_D}lu-bd2LXYjN9^3V{*_+x1 z_-rBb+0^;$Xy&u2^VwqNv#ImhQs%R%^I0YH+0^-LIrG`n`D`Wg+0^;$Smv`KJ~NZ% zv+{iAvnlb}8KvcxI*5I8M}77dfcF8+65zAj_1Qh6`Yf5sc;G0<<1|8_y*ThWf-Swb z$-+M(Z3`FvM1c1RKqzn%1&&eRH41!S0iU*0R(3A4ay~WjoU4Mk9=2_`C)MgSZPEJ{21oRvC{33zcE63Vm6PBjGWl zSfIGaOijp$)s+_qLNl&6Lbn#FP{lgfD5kD^WBa-%h2b*L?T_g`@_-iX_@=JxZpFRi z!nf3nY3SQZrC2T%HE$GMRWFr`<%Rjur%FaOq+6;iS5_-WD~pR2_t>J~9xtyPT`ez^ zSNO`p;&OTUP?4RgHv&;lmX{0>%c83yQ9RYW;t3TR5t+gDH;@)+bNc9b`Ik2_$C?LF z0r2@@+@a08;;vT5y@Y%#`A?b%`Xzwh0QdkvjsS-V@Gt?)5Cj!S{`&+-?zA@vklbe$ z1?DO6MVjiG--2Fsy1N-?f7i)pwF;Y4dXkPruf)RLWxc-3%etJ&?~S&qp-i?uq`*HY z@LxKJ%e{jX2DI(zAGwaziQJP`CvpofK> z4)BHp{LTS>m;-Lf11Iyq6Zus4+!bbqeFNzKvBC7GKgK2e%MK}Z6Hixw%ObnKCRilA zIP`dEdJvf=WCwz}rsBY3t4Y7QS`!}gBURr5jN8g3L=2zuz?{MxvNUvvL#eq~4b_@} zP47(CIXld6vW;Mv9S{sR4GD&yUGre*O_$eUNPLElIV1+8^gfSyvTa1RjmWkU**0Qq z+lW4oDRX!2zT7l2bH-LBkBFS4MjcWne~$pkZt10A+-a4&uaZu=dx3Pz-CHjrr%Zv< z6nK;Z-=@Gl7VrlP_~Z}-6-Z&l20mv4kJ!LtHgL`czUlxM9N^a6RhGMBB3M=mUv=HH z3+3*(f*~t~Co?1lq@F&fEvyf-)U$J`hg`dI_kR?4+5&!SO=h{9C5veyL!UD}`H!Yi z+rGS1YB469JZ<}_5w&fyX<5IRIBol#(N{GDor$phuPYF?^XUO#0XYi;)bB2PXIlz) z_x)+B!{TQx;G6}#ZUOIEt-_r-!0it3wc#@Niw+FdiFK=SI3b2sREgQyUPM_rCSA4g!=pP!ha5bn#=yQhD z-kXW#Qz@3eK!H~*;I9+9dmwjQlE|grN)?wzvo$H!M^wcBj%ilJw@RmzsCoA}%4{FV z&@r{>NQ&QoPB1!J&(j8j!|}r?UJ2BSSAc#&%*F723D3Ehvr6ez2wIK18C#(M+Hp)09HM#$^ZZW literal 1763 zcmV<91|0c8RzVmQ2<00000000B+n_p-gMI6V!Gjn@){hQPZVxcg!LQGBWa%ujxs94fcqO~o7 ziY`9oetxvk+Qn}BZHVj?q`^mEm5qLi&N@y2=UI1%Jcn#6EIgUOhAtMS=u z4$I7>w1ur=6K-xq<0T`CW`yhNY2o_1SvjpcwrQu!uM{nd9V?4nd0VKYt%_#7fo3hI z+2%mAmeZ^+(5&S&>kl+*In4$F&00>g!9cT?(`+cvtmQP@5@=RKGquz-OY{VqwTNbW zrEAXVgM>CNs%94fTmjHdfKBt&?9qBP^M=wGIGT+SjnHG)J3c`$r+Ot3euESu9Q~RA zR|r5Tu$}^2C~%enA2EQ1d{NeJigLs^@NiOE*^FI?;WA&VmWyHTD6-1e7P3rR6wV9# z+9HK86_0n1N~!o`rkLisZSYZThx+AzP6;Db#Wu~)^Fu0Q3lDfgwxG)`_kw(@M zF4x@|J2~!1TV`ErCg!`^>cZ8w3#FTuTX>sZ!#-E=Z6&AjT~ar^3*S4g)TFyL9?zQn zF;}0AC1oa_h$VV^;v3^iPMXR1z~I2xz~+IzzJcVHKA{_WVrcVNqBk+55B2s9CI&lW zd?YhziHxun_qxcMv7~fFY$SKZVQDL2t6@jz%9J)YZ6%zPo)p})dFd46(&4U9`CH^E zOHaEzB^|yY-)Dc^$psE~mp3!YHC0yl~*~waB#3&xF%bNY& zR&Gq)w(RyU-EHM#<9|L}F(n*R%@mZTRghA_ri-LYkivQZ3;=kj7FK9((m#?vaRnjI zd4EZcFqZ&)2;c_*VFGj!-~a(s4Z=i8nmay5QtRc=oo=H~F@1M(*YM?y4qo*-sSsodQ>BHSCsm60Opbx4;b)N2>2%i+^qqlT6JkbU2Yc1DU2NKN+&>!kBW?(5;>gRprRj&Med~> znW;v;%E^I<+Q_b&B=ku$UbBl%-&okB%nu+$clgVdMI$tshurN|cXL4XRX)p-{#x3nT{l-xnJ+APtlq>l=F7T702`dGa5L2g||`XdEg z2E1J(Uj)Dpp8YxYzJ&j6MU(jEf+kN9d+C|PFV<-ilakwdcgdN=AJ>0ZHQ?wu#D6cq zA&&Sv00Y7dRcz#0y0+)7;@RUptVr8q3^>7n^9;DmfTu%1R0HnOfG2AE#fLTEhz6Y2 zfQuUNr3Q3{fw#iIw_)Gu%NEfuUK;>;@vXysP4$cG&CUK^{ccguh@G^uhT!_F9NZPj zqK_hTLX|)G^AT%*83OsVX<2+s~EA9RdkP;xJKBQ;?QUatTDttLb`?L8- z*}a62Qus#EM59&+*>M8AMu0cxx54Dx>;{uxZfr2=qChVN_ENy2zzY=k;`;C73^-PM zgULAtyvKk~8SpCumWO~tA>fn-eD;4gnD`}GEJ6jI=6qe{Mkx^Fh}$Md{0Cz_PukK+ F002~0R!0B; From f136e64bd2107e35990cff7f11423e0f90fe8f39 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Tue, 28 May 2024 15:19:23 +0200 Subject: [PATCH 89/90] refactor: Fix message text --- src/linter/ui5Types/asyncComponentFlags.ts | 4 ++-- .../rules/snapshots/AsyncComponentFlags.ts.md | 4 ++-- .../snapshots/AsyncComponentFlags.ts.snap | Bin 1902 -> 1902 bytes 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/linter/ui5Types/asyncComponentFlags.ts b/src/linter/ui5Types/asyncComponentFlags.ts index 8555b7d03..5967e91dd 100644 --- a/src/linter/ui5Types/asyncComponentFlags.ts +++ b/src/linter/ui5Types/asyncComponentFlags.ts @@ -359,13 +359,13 @@ function reportResults({ if (AsyncPropertyStatus.parentPropNotSet === rootViewAsyncFlag) { // sap.ui5/rootView is not set at all, so skip it in the message - message = `Routing is not configured to load its targets asynchronously.`; + message = `Component Routing is not configured to load its targets asynchronously.`; messageDetails = `{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. ` + `Implement sap.ui.core.IAsyncContentCreation interface in ${fileName} or set the "async" flag for ` + `"sap.ui5/routing/config" in the component manifest.`; } else if (AsyncPropertyStatus.parentPropNotSet === routingAsyncFlag) { // sap.ui5/routing/config is not set at all, so skip it in the message - message = `Root View is not configured to load its views asynchronously.`; + message = `Component Root View is not configured to load its views asynchronously.`; messageDetails = `{@link topic:676b636446c94eada183b1218a824717 Use Asynchronous Loading}. ` + `Implement sap.ui.core.IAsyncContentCreation interface in ${fileName} or set the "async" flag for ` + `"sap.ui5/rootView" in the component manifest.`; diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md index 5a31a4775..31565e140 100644 --- a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md +++ b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.md @@ -363,7 +363,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: 'Root View is not configured to load its views asynchronously.', + message: 'Component Root View is not configured to load its views asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flag for "sap.ui5/rootView" in the component manifest.', ruleId: 'ui5-linter-async-component-flags', severity: 2, @@ -388,7 +388,7 @@ Generated by [AVA](https://avajs.dev). column: 9, fatal: undefined, line: 6, - message: 'Routing is not configured to load its targets asynchronously.', + message: 'Component Routing is not configured to load its targets asynchronously.', messageDetails: 'Use Asynchronous Loading (https://ui5.sap.com/1.120/#/topic/676b636446c94eada183b1218a824717). Implement sap.ui.core.IAsyncContentCreation interface in Component.js or set the "async" flag for "sap.ui5/routing/config" in the component manifest.', ruleId: 'ui5-linter-async-component-flags', severity: 2, diff --git a/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap b/test/lib/linter/rules/snapshots/AsyncComponentFlags.ts.snap index fdb93843c49bb7dc9c9e8597f812a8fbd2ea8347..20d8a8dda6c723ef0c22993ea859743d426b6d27 100644 GIT binary patch literal 1902 zcmV-!2a)(eRzVSuU_ufEt?jO!sY_4S&{e&gMSPHGGzkfkT!Io2FF{1a1VhNvg%CspBf$q>M10VY zmvD*?QBfZ>J^yZ}Z+2#HZs&I9=zZDguBqy(-|yF--><)2bJkxCl>4ZD;bmc@352;z zgd*a>ZR|c#v`PphsifBBH~qXBJ>r=4E7V+X}d;5k&2F~I5f>uHd0@h@wwr_okPA= z@MR!QaZ~GF^O&kPR477IJgu8Es%@H4p)R!MRiRVE>|N(kD8p*+l?pw!vwCdT+h%WS z8{o5r%x6>Qv%{Isrp{-Jna`%qXG@vSrp{-T%x6>Qv*pZZQ|Ggl%x6>Qvm=?$hWN}( zn$ODfna`%gXQz~wTk0V8@g4QqTL9h%FiU`2w(GNdNA+1UmGQt)j>l<)KKt>&X9%|R z-X;tGkhCpa_!9x%Cjg)T&USJg}9VtHY{^qG=T4e6FD%azs2;mYD-#XYhpxW~&YhgZuB zWx6uljS8t#IoqBNEA;ruXs#_Mug^AB)E|(WHK}&^0_OR4B6&j zV=7`=m}J3huDQ-R<_Em0nXe)?*BW`L6tzrNYME-TX~s>B$|S~}O9oE{a=V7F^HBOi zo3zbxQ5=X9Ugwa-a_LaeoaCYABo1|lIMkd?`UcWsO+?acv_pXoU``($FaOFW=2-Ip zDgf>n#vR(cEADP}yq1tBlK-TMpmzZL8o&ntas)U?fJX>mh9Iaw^4}vsa;KdmKysg1 z6qu*L7ig+$ehYfl>F#EneO)J?)+%gH=}9^gy%Gy|m-YHCFY96^zc<>dhBDdukOF_F zz<=l2ae}~$MdP~xl7Cpdk4_}6NBkbe~b(GmmN~-CY~+nu-IDttS2IYE5{|k5qjNFm5ZC5HWnp19J**$kNau4y5K{HB@T? zHoY@l=j<@Q$u@#vc0e%PI3yT;cEy9CH(g$ZA@Mmn=8zbW()+yT$sQxJ$B67PB72M& z+hatZ*Oa-tcVBKAnK@&tl1D^NQlkzjlb<6%^0f5wFz&R<-Jg?AxqF^;%iUW)MoyUm zCn@kK1-?yzdoAD(7VxPd2r7`miVb|;2EJ?qkJ-Q(8~CaNoOgg*bC+4}j)`DdDSX*= z&n}d^;|hkX6rRkG7?67U?6$Bz%u>(Jr52B_a%_Rh8x z?(XqPtHa`FE#Qm=ylw&SS*^mIIl%1>@U`JG_e&0N)&bsjfIm9GzZ{^J1764jzfa5D zdv;Lf-k;(6%4wPpOn}TiYF`do-^L=E+F7MnxNp>)uEzvZH~i zskmB8Cb}+zAc?$K3y*QbqBu0NE*OuEs&gY<9t0Z)nW;(LiBoObeZ*spNa&9|423+gy$ZYfFm1V(~#Dehs#d4*xI={Gdc=d?qx+}h0S@aK#S-2WhBlOur zYTuBFoIemWXlsmus%(-uZnA84&+UaqQ4(*}&5_@KYQ3l@0va1|D{RXL7)A oFL%dK+9f-MuuLqzn#JN>46H0S4$Y0`YRQfN2eQ9BDH%-w0H;K-+W-In delta 1893 zcmV-r2b%cq4(<+rK~_N^Q*L2!b7*gLAa*kf0{}kSxl;9aAvU7qI+hU@9W~TCgEGk< zZoi+|iAR%pDl{L92mk;800003?VDeW8%G_-zcagQJ5AEN5RiDOG&)deXkwo)cfL#2 zBBG>1p??ypwxU%fnA@GTCtdGYJF|B^As(voudP}knpU8HBBZoJ2+@LC^|4ij5JI9= z#RD%0@c>m{N@3KBkQ~U3gxpPlj}r^TIY9QgYE4AEDo%yI0-3=J1f&&=k+==8S5aW>lzu3$1xo=+rR#)_D}lu-bd2LXYjN z9^3V{*_+x1_-rBb+0^;$Xy&u2^VwqNv#ImhQs%R%^I0YH+0^-LIrG`n`D`Wg+0^;$ zSmv`KJ~NZ%v+{iAvnlb}8KvcxI*5I8M}77dfcF8+65zAj_1Qh6`Yf5sc;G0<<1|8_ zy*TiHIf5;{x5>gkB5ey7{zQQH2|y@t69tY@;57<-U;&@DQ&x5^vvNK)@tmuIxE{7` zxF^->G;P>?m*1aivjZ85cE4PzE#Ed%=lz$vMrHRYW!QsKtTP^Z>^>D68CDsO1Phg6 zt_powjU(YPqgbH0$4pJgh}D%B2SPKhH$u067O7ChI@lm5b$t`O>FKMm3~csw`JlD@QAfixv0S zqTn7cuN+-1FO*mK%EIDudHGP0ovJqiQBRha3=zwst0GZ6)x6>f6&ewm6OrIXs*uTl z(1^(Au3$1`n}dz1h-qPx1+%&4I_H=l@Tz9Mir8FhLC8otg$=?iVrHp@kEAWnImw=9-RM}p=gk2EK7q&vis=4{e8kQQqql4heF3UmN- z`sjH1mp3uTng>t;@cCifq0PJEu2#o?y@Y%#`A?b%`Xzwh0QdkvjsS-V@Gt?)5Cj!S z{`&+-?zA@vklbe$1?DO6MVjiG--2Fsy1N-?f7i)pwF;Y4dXkPruf)RLWxc-3%etJ& z?~S&qp-i?uq`*HY@LxKJ%e{jX2DI(zAGwaziQJP`Cvpo^$+^CMN?0*u?rB}5FL^1z(J z8?rQXh(oElSPj*hfKBgA*Eu_X%x|)dV3-{c3^xr4hM!&YVCYSk*I`I}hK@NT2Bh>p zk9o3fM7E8{wh`GjVr<)pK94DLckRC1G%|C>Rwa*!oTNq_QYL?o0LgCYrD5D@mAkK! zPPu!5bj#gaFCwQ*fzuRtlmg$Tz&#f52MhS*5Cj!SVZ{bMX9JJez+*OlaLxw4>HrrU z;MUw#mb+sjSXK&Ob=|WIcE?IST{S?=E|1TMBng_x)+B!{TQx;G6}#ZUOIEt-_r-!0it3wc#@Niw+FdiFK=SI3b2sREgQyUPCx^8~C*i{MiN`a)4)Yz`Iv_Iw Date: Tue, 28 May 2024 15:16:52 +0200 Subject: [PATCH 90/90] refactor: Revert "refactor: Extract virBasePath from filePaths" This reverts commit adae2acddc7fdef5cadc1ae7a7c9cc5fd7e33021. --- src/linter/linter.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/linter/linter.ts b/src/linter/linter.ts index cc81d0cbc..13c51523c 100644 --- a/src/linter/linter.ts +++ b/src/linter/linter.ts @@ -87,19 +87,16 @@ export async function lintProject({ export async function lintFile({ rootDir, pathsToLint, namespace, reportCoverage, includeMessageDetails, }: LinterOptions): Promise { + const reader = createReader({ + fsBasePath: rootDir, + virBasePath: namespace ? `/resources/${namespace}/` : "/", + }); let resolvedFilePaths; - let virBasePath = ""; if (pathsToLint?.length) { const absoluteFilePaths = resolveFilePaths(rootDir, pathsToLint); resolvedFilePaths = transformFilePathsToVirtualPaths( absoluteFilePaths, rootDir, "/", rootDir); - // Extract the (virtual) path from the filename - virBasePath = resolvedFilePaths[0].split("/").slice(0, -1).join("/"); } - const reader = createReader({ - fsBasePath: rootDir, - virBasePath: `${virBasePath}/`, - }); const res = await lint(reader, { rootDir,