@ui5/linter
Version:
A static code analysis tool for UI5
123 lines • 6 kB
JavaScript
import ManifestReporter from "./ManifestReporter.js";
import jsonMap from "json-source-map";
import { deprecatedLibraries, deprecatedComponents } from "../../utils/deprecations.js";
import { MESSAGE } from "../messages.js";
const deprecatedViewTypes = ["JSON", "HTML", "JS", "Template"];
export default class ManifestLinter {
#reporter;
#content;
#resourcePath;
#context;
constructor(resourcePath, content, context) {
this.#resourcePath = resourcePath;
this.#content = content;
this.#context = context;
}
// eslint-disable-next-line @typescript-eslint/require-await
async lint() {
try {
const source = this.#parseManifest(this.#content);
this.#reporter = new ManifestReporter(this.#resourcePath, this.#context, source);
this.#analyzeManifest(source.data);
}
catch (err) {
const message = err instanceof Error ? err.message : String(err);
this.#context.addLintingMessage(this.#resourcePath, MESSAGE.PARSING_ERROR, { message });
}
}
#parseManifest(manifest) {
return jsonMap.parse(manifest);
}
#analyzeManifest(manifest) {
const { resources, models, dependencies, rootView, routing } = (manifest["sap.ui5"] ?? {});
const { dataSources } = (manifest["sap.app"] ?? {});
// Detect deprecated libraries:
const libKeys = (dependencies?.libs && Object.keys(dependencies.libs)) ?? [];
libKeys.forEach((libKey) => {
if (deprecatedLibraries.includes(libKey)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_LIBRARY, {
libraryName: libKey,
}, `/sap.ui5/dependencies/libs/${libKey}`);
}
});
// Detect deprecated components:
const componentKeys = (dependencies?.components && Object.keys(dependencies.components)) ?? [];
componentKeys.forEach((componentKey) => {
if (deprecatedComponents.includes(componentKey)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_COMPONENT, {
componentName: componentKey,
}, `/sap.ui5/dependencies/components/${componentKey}`);
}
});
// Detect deprecated type of rootView:
if (typeof rootView === "object" && rootView.type && deprecatedViewTypes.includes(rootView.type)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_VIEW_TYPE, {
viewType: rootView.type,
}, "/sap.ui5/rootView/type");
}
// Detect deprecated view type in routing.config:
if (routing?.config && routing.config.viewType && deprecatedViewTypes.includes(routing.config.viewType)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_VIEW_TYPE, {
viewType: routing.config.viewType,
}, "/sap.ui5/routing/config/viewType");
}
// Detect deprecations in routing.targets:
const targets = routing?.targets;
if (targets) {
for (const [key, target] of Object.entries(targets)) {
// Check if name starts with module and viewType is defined:
const name = target.name ?? target.viewName;
if (name && name.startsWith("module:")) {
if (target.viewType) {
this.#reporter?.addMessage(MESSAGE.REDUNDANT_VIEW_CONFIG_PROPERTY, {
propertyName: "viewType",
}, `/sap.ui5/routing/targets/${key}/viewType`);
}
}
const pathToViewObject = `/sap.ui5/routing/targets/${key}`;
// Detect deprecated view type:
if (target.viewType && deprecatedViewTypes.includes(target.viewType)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_VIEW_TYPE, {
viewType: target.viewType,
}, `${pathToViewObject}/viewType`);
}
}
}
if (resources?.js) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_MANIFEST_JS_RESOURCES, "/sap.ui5/resources/js");
}
const modelKeys = (models && Object.keys(models)) ?? [];
modelKeys.forEach((modelKey) => {
const curModel = (models?.[modelKey]) ?? {};
if (!curModel.type) {
const curDataSource = dataSources && curModel.dataSource &&
dataSources[curModel.dataSource];
if (curDataSource &&
/* if not provided dataSource.type="OData" */
(curDataSource.type === "OData" || !curDataSource.type)) {
curModel.type = curDataSource.settings?.odataVersion === "4.0" ?
"sap.ui.model.odata.v4.ODataModel" :
"sap.ui.model.odata.v2.ODataModel";
}
// There are other types that can be found in sap/ui/core/Component, but the one
// we actually care here is just the "sap.ui.model.odata.v4.ODataModel"
}
if (curModel.type && [
"sap.ui.model.odata.ODataModel",
"sap.zen.dsh.widgets.SDKModel",
].includes(curModel.type)) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_CLASS, {
className: curModel.type,
details: `{@link ${curModel.type}}`,
}, `/sap.ui5/models/${modelKey}/type`);
}
if (curModel.type === "sap.ui.model.odata.v4.ODataModel" &&
curModel.settings && "synchronizationMode" in curModel.settings) {
this.#reporter?.addMessage(MESSAGE.DEPRECATED_ODATA_MODEL_V4_SYNCHRONIZATION_MODE, {
modelName: modelKey,
}, `/sap.ui5/models/${modelKey}/settings/synchronizationMode`);
}
});
}
}
//# sourceMappingURL=ManifestLinter.js.map