Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Detect deprecations in ui5.yaml (in root directory) #39

Merged
merged 12 commits into from
Apr 17, 2024
Merged
423 changes: 217 additions & 206 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@ui5/logger": "^3.0.0",
"@ui5/project": "^3.9.1",
"chalk": "^5.3.0",
"data-with-position": "^0.5.0",
"figures": "^6.1.0",
"he": "^1.2.0",
"json-source-map": "^0.6.1",
Expand Down
2 changes: 2 additions & 0 deletions src/linter/lintWorkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {AbstractAdapter} from "@ui5/fs";
import lintXml from "./xmlTemplate/linter.js";
import lintJson from "./manifestJson/linter.js";
import lintHtml from "./html/linter.js";
import lintUI5Yaml from "./yaml/linter.js";
import {taskStart} from "../util/perf.js";
import TypeLinter from "./ui5Types/TypeLinter.js";
import LinterContext, {LintResult, LinterParameters, LinterOptions} from "./LinterContext.js";
Expand All @@ -20,6 +21,7 @@ export default async function lintWorkspace(
lintXml(params),
lintJson(params),
lintHtml(params),
lintUI5Yaml(params),
]);

const typeLinter = new TypeLinter(params);
Expand Down
2 changes: 2 additions & 0 deletions src/linter/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,8 @@ function transformVirtualPathToFilePath(
return path.join(srcFsBasePath, posixPath.relative(srcVirBasePath, virtualPath));
} else if (testFsBasePath && testVirBasePath && virtualPath.startsWith(testVirBasePath)) {
return path.join(testFsBasePath, posixPath.relative(testVirBasePath, virtualPath));
} else if (virtualPath.startsWith("/")) {
return posixPath.relative("/", virtualPath);
} else {
throw new Error(
`Resource path ${virtualPath} is not located within the virtual source or test directories of the project`);
Expand Down
22 changes: 1 addition & 21 deletions src/linter/manifestJson/ManifestLinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,14 @@ import ManifestReporter from "./ManifestReporter.js";
import {LintMessageSeverity, ResourcePath} from "../LinterContext.js";
import jsonMap from "json-source-map";
import LinterContext from "../LinterContext.js";
import deprecatedLibraries from "../../utils/deprecatedLibs.js";

interface locType {
line: number;
column: number;
pos: number;
}

const deprecatedLibraries: string[] = [
"sap.ca.scfld.md",
"sap.ca.ui",
"sap.fe.common", // Internal, removed in 1.110
"sap.fe.plugins", // Internal, removed in 1.102
"sap.fe.semantics", // Internal, removed in 1.104
"sap.landvisz", // Removed in 1.120
"sap.makit",
"sap.me",
"sap.sac.grid", // Removed in 1.114
"sap.ui.commons",
"sap.ui.suite",
"sap.ui.ux3",
"sap.ui.vtm",
"sap.uiext.inbox",
"sap.webanalytics.core",
"sap.zen.commons",
"sap.zen.crosstab",
"sap.zen.dsh",
];

const deprecatedComponents: string[] = [
"sap.zen.dsh.fioriwrapper",
];
Expand Down
83 changes: 83 additions & 0 deletions src/linter/yaml/YamlLinter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {LintMessageSeverity} from "../LinterContext.js";
import LinterContext from "../LinterContext.js";
import deprecatedLibraries from "../../utils/deprecatedLibs.js";
import {DataWithPosition, fromYaml, getPosition} from "data-with-position";

interface YamlWithPosInfo extends DataWithPosition {
framework?: {
libraries?: {
name: string;
}[];
};
positionKey?: {
end: {
column: number;
line: number;
};
start: {
column: number;
line: number;
};
};
}

export default class YamlLinter {
#content;
#resourcePath;
#context: LinterContext;

constructor(resourcePath: string, content: string, context: LinterContext) {
this.#content = content;
this.#resourcePath = resourcePath;
this.#context = context;
}

// eslint-disable-next-line @typescript-eslint/require-await
async lint() {
try {
// Split Yaml file into part documents by '---' separator
const allDocuments: string[] = this.#content.split(/(?:\r\n|\r|\n)---/g);

// Calculate the starting line number of each part document
let lineNumberOffset = 0;
allDocuments.forEach((document: string) => {
// Parse content only of the current part
const parsedYamlWithPosInfo: YamlWithPosInfo = this.#parseYaml(document);
// Analyze part content with line number offset
this.#analyzeYaml(parsedYamlWithPosInfo, lineNumberOffset);
// Update line number offset for next part
lineNumberOffset += document.split(/\r\n|\r|\n/g).length;
});
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
this.#context.addLintingMessage(this.#resourcePath, {
severity: LintMessageSeverity.Error,
message,
ruleId: "ui5-linter-parsing-error",
fatal: true,
});
}
}

#parseYaml(content: string): YamlWithPosInfo {
// Create JS object from YAML content with position information
return fromYaml(content) as YamlWithPosInfo;
}

#analyzeYaml(yaml: YamlWithPosInfo, offset: number) {
// Check for deprecated libraries
yaml?.framework?.libraries?.forEach((lib) => {
if (deprecatedLibraries.includes(lib.name.toString())) {
const positionInfo = getPosition(lib);
this.#context.addLintingMessage(this.#resourcePath, {
ruleId: "ui5-linter-no-deprecated-api",
severity: LintMessageSeverity.Error,
fatal: undefined,
line: positionInfo.start.line + offset,
column: positionInfo.start.column,
message: `Use of deprecated library '${lib.name}'`,
});
}
});
}
}
29 changes: 29 additions & 0 deletions src/linter/yaml/linter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {LinterParameters} from "../LinterContext.js";
import YamlLinter from "./YamlLinter.js";
import {Resource} from "@ui5/fs";

export default async function lintUI5Yaml({context}: LinterParameters) {
let ui5YamlResources: Resource[];
const pathsToLint = context.getPathsToLint();
const reader = context.getRootReader();
if (pathsToLint?.length) {
ui5YamlResources = [];
await Promise.all(pathsToLint.map(async (resourcePath) => {
if (!resourcePath.endsWith(".yaml")) {
return;
}
const resource = await reader.byPath(resourcePath);
if (!resource) {
throw new Error(`Resource not found: ${resourcePath}`);
}
ui5YamlResources.push(resource);
}));
} else {
ui5YamlResources = await reader.byGlob("/{ui5.yaml,*-ui5.yaml,*.ui5.yaml,ui5-*.yaml}");
}

await Promise.all(ui5YamlResources.map(async (resource: Resource) => {
const linter = new YamlLinter(resource.getPath(), await resource.getString(), context);
await linter.lint();
}));
}
1 change: 1 addition & 0 deletions src/untyped.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ declare module "@ui5/project" {
interface Project {
getNamespace: () => ProjectNamespace;
getReader: (options: import("@ui5/fs").ReaderOptions) => import("@ui5/fs").AbstractReader;
getRootReader: () => import("@ui5/fs").AbstractReader;
getRootPath: () => string;
getSourcePath: () => string;
_testPath: string; // TODO UI5 Tooling: Expose API for optional test path
Expand Down
22 changes: 22 additions & 0 deletions src/utils/deprecatedLibs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const deprecatedLibs: string[] = [
maxreichmann marked this conversation as resolved.
Show resolved Hide resolved
"sap.ca.scfld.md",
"sap.ca.ui",
"sap.fe.common", // Internal, removed in 1.110
"sap.fe.plugins", // Internal, removed in 1.102
"sap.fe.semantics", // Internal, removed in 1.104
"sap.landvisz", // Removed in 1.120
"sap.makit",
"sap.me",
"sap.sac.grid", // Removed in 1.114
"sap.ui.commons",
"sap.ui.suite",
"sap.ui.ux3",
"sap.ui.vtm",
"sap.uiext.inbox",
"sap.webanalytics.core",
"sap.zen.commons",
"sap.zen.crosstab",
"sap.zen.dsh",
];

export default deprecatedLibs;
11 changes: 11 additions & 0 deletions test/fixtures/linter/projects/com.ui5.troublesome.app/ui5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
specVersion: '3.0'
metadata:
name: com.ui5.troublesome.app
type: application
framework:
name: OpenUI5
version: "1.121.0"
libraries:
- name: sap.m
- name: sap.ui.core
- name: sap.landvisz
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ framework:
version: "1.120.6"
libraries:
- name: sap.ui.core
- name: sap.landvisz
11 changes: 11 additions & 0 deletions test/fixtures/linter/rules/NoDeprecatedApi/ui5.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
specVersion: '3.0'
flovogt marked this conversation as resolved.
Show resolved Hide resolved
metadata:
name: com.ui5.troublesome.app
type: application
framework:
name: OpenUI5
version: "1.121.0"
libraries:
- name: sap.m
- name: sap.ui.core
- name: sap.landvisz
Binary file not shown.
Loading