From ea07052bdd8e1f762e8680fae9aedee813504811 Mon Sep 17 00:00:00 2001 From: Matthias Osswald Date: Tue, 3 Dec 2024 11:24:45 +0100 Subject: [PATCH 1/3] docs: Add documentation for all available rules MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Florian Vogt Co-authored-by: Günter Klatt <57760635+KlattG@users.noreply.github.com> --- README.md | 35 +++++++++++++++++++++ docs/Rules.md | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) create mode 100644 docs/Rules.md diff --git a/README.md b/README.md index ee6dde49..bf222c88 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,35 @@ [![npm Package Version](https://badge.fury.io/js/%40ui5%2Flinter.svg)](https://www.npmjs.com/package/@ui5/linter) [![Coverage Status](https://coveralls.io/repos/github/SAP/ui5-linter/badge.svg)](https://coveralls.io/github/SAP/ui5-linter) +- [UI5 Linter](#ui5-linter) + - [Description](#description) + - [Features](#features) + - [Rules](#rules) + - [Requirements](#requirements) + - [Installation](#installation) + - [Usage](#usage) + - [Options](#options) + - [`--details`](#--details) + - [`--format`](#--format) + - [`--ignore-pattern`](#--ignore-pattern) + - [`--config`](#--config) + - [`--ui5-config`](#--ui5-config) + - [Configuration](#configuration) + - [Configuration File Location](#configuration-file-location) + - [Supported Configuration File Names](#supported-configuration-file-names) + - [Configuration File Format](#configuration-file-format) + - [ESM (ECMAScript Modules):](#esm-ecmascript-modules) + - [CommonJS:](#commonjs) + - [Configuration Options](#configuration-options) + - [Directives](#directives) + - [Specifying Rules](#specifying-rules) + - [Scope](#scope) + - [Internals](#internals) + - [Support, Feedback, Contributing](#support-feedback-contributing) + - [Security / Disclosure](#security--disclosure) + - [Code of Conduct](#code-of-conduct) + - [Licensing](#licensing) + ## Description UI5 linter is a static code analysis tool for UI5 projects. @@ -27,6 +56,12 @@ UI5 linter scans your UI5 project and detects issues that might interfere with i > [!NOTE] > While UI5 linter already provides many detection features, it is not yet covering all aspects and best practices for UI5 2.x. The intention of UI5 linter is to detect as many issues as possible that a project running with UI5 2.x might be facing. However, you'll still need to test your UI5 project with UI5 2.x as soon as it is made available. To reveal additional issues, the UI5 team plans to release more versions of UI5 linter over the next months. +## Rules + +UI5 linter comes with a set of predefined rules that are enabled by default. You can disable specific rules in the code via [Directives](#directives). + +A list of all available rules can be found on the [Rules](./docs/Rules.md) page. + ## Requirements - [Node.js](https://nodejs.org/) Version v20.11.x, v22.0.0, or higher diff --git a/docs/Rules.md b/docs/Rules.md new file mode 100644 index 00000000..40df46ab --- /dev/null +++ b/docs/Rules.md @@ -0,0 +1,84 @@ +# Rules Reference + +- [Rules Reference](#rules-reference) + - [async-component-flags](#async-component-flags) + - [csp-unsafe-inline-script](#csp-unsafe-inline-script) + - [no-deprecated-api](#no-deprecated-api) + - [no-deprecated-component](#no-deprecated-component) + - [no-deprecated-control-renderer-declaration](#no-deprecated-control-renderer-declaration) + - [no-deprecated-library](#no-deprecated-library) + - [no-deprecated-theme](#no-deprecated-theme) + - [no-globals](#no-globals) + - [no-pseudo-modules](#no-pseudo-modules) + - [parsing-error](#parsing-error) + - [ui5-class-declaration](#ui5-class-declaration) + +## async-component-flags + +Checks whether a Component is configured for asynchronous loading via the `sap.ui.core.IAsyncContentCreation` interface in the Component metadata or via `async` flags in the `manifest.json`. + +**Related information** +- [Use Asynchronous Loading](https://ui5.sap.com/#/topic/676b636446c94eada183b1218a824717) +- [Component Metadata](https://ui5.sap.com/#/topic/0187ea5e2eff4166b0453b9dcc8fc64f) +- [sap.ui.core.IAsyncContentCreation](https://ui5.sap.com/1.120/#/api/sap.ui.core.IAsyncContentCreation) + +## csp-unsafe-inline-script + +Checks whether inline scripts are used in HTML files in accordance with Content Security Policy (CSP) best practices. + +**Related information** +- [Content Security Policy](https://ui5.sap.com/#/topic/fe1a6dba940e479fb7c3bc753f92b28c) + +## no-deprecated-api + +Checks whether deprecated APIs, features or parameters are used in the project. + +**Related information** +- [Best Practices for Developers](https://ui5.sap.com/#/topic/28fcd55b04654977b63dacbee0552712) + +## no-deprecated-component + +Checks for dependencies to deprecated components in `manifest.json`. + +**Related information** +- [Deprecated Themes and Libraries](https://ui5.sap.com/#/topic/a87ca843bcee469f82a9072927a7dcdb) + +## no-deprecated-control-renderer-declaration + +Checks whether the renderer of a control is declared correctly. + +## no-deprecated-library + +Checks for dependencies to deprecated libraries in `manifest.json` and `ui5.yaml`. + +**Related information** +- [Deprecated Themes and Libraries](https://ui5.sap.com/#/topic/a87ca843bcee469f82a9072927a7dcdb) + +## no-deprecated-theme + +Checks for usage of deprecated themes in the code and HTML files. + +**Related information** +- [Deprecated Themes and Libraries](https://ui5.sap.com/#/topic/a87ca843bcee469f82a9072927a7dcdb) + +## no-globals + +Checks for the usage of global variables in the code. + +**Related information** +- [Best Practices for Developers](https://ui5.sap.com/#/topic/28fcd55b04654977b63dacbee0552712) + +## no-pseudo-modules + +Checks for dependencies to pseudo modules in the code. + +**Related information** +- [Best Practices for Loading Modules - Migrating Access to Pseudo Modules](https://ui5.sap.com/#/topic/00737d6c1b864dc3ab72ef56611491c4) + +## parsing-error + +Syntax/parsing errors that appear during the linting process are reported with this rule. + +## ui5-class-declaration + +Checks whether the declaration of UI5 classes is correct. This rule only applies to TypeScript code where built-in ECMAScript classes are used instead of an `.extend()` call. From 81b2e6aad0eea739452a48f447171cd13966cbf2 Mon Sep 17 00:00:00 2001 From: Max Reichmann Date: Tue, 3 Dec 2024 12:04:52 +0100 Subject: [PATCH 2/3] feat: Add `ruleId` to Markdown format output The `ruleId` links to the corresponding rule documentation. --- src/cli.ts | 7 ++- src/cli/base.ts | 3 +- src/cli/middlewares/logger.ts | 4 +- src/cli/version.ts | 7 ++- src/formatter/markdown.ts | 18 ++++--- test/lib/cli.ts | 24 ++++++---- test/lib/cli/middlewares/logger.ts | 10 ++-- test/lib/cli/version.ts | 17 +++++-- test/lib/formatter/markdown.ts | 6 +-- test/lib/formatter/snapshots/markdown.ts.md | 44 +++++++++--------- test/lib/formatter/snapshots/markdown.ts.snap | Bin 517 -> 603 bytes 11 files changed, 82 insertions(+), 58 deletions(-) diff --git a/src/cli.ts b/src/cli.ts index 5587b9ba..b0bb6023 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -2,7 +2,7 @@ import yargs from "yargs"; import {hideBin} from "yargs/helpers"; import base from "./cli/base.js"; import {fileURLToPath} from "node:url"; -import {setVersion} from "./cli/version.js"; +import {getFormattedVersion, setVersionInfo} from "./cli/version.js"; import {createRequire} from "module"; export default async function () { @@ -17,10 +17,9 @@ export default async function () { const require = createRequire(import.meta.url); const pkg = require("../package.json") as {version: string}; const ui5LintJsPath = fileURLToPath(new URL("../bin/ui5lint.js", import.meta.url)); - const pkgVersion = `${pkg.version} (from ${ui5LintJsPath})`; - setVersion(pkgVersion); - cli.version(pkgVersion); + setVersionInfo(pkg.version, ui5LintJsPath); + cli.version(getFormattedVersion()); // Explicitly set script name to prevent windows from displaying "ui5-linter.js" cli.scriptName("ui5lint"); diff --git a/src/cli/base.ts b/src/cli/base.ts index 544b82be..df4f5d54 100644 --- a/src/cli/base.ts +++ b/src/cli/base.ts @@ -9,6 +9,7 @@ import baseMiddleware from "./middlewares/base.js"; import chalk from "chalk"; import {isLogLevelEnabled} from "@ui5/logger"; import ConsoleWriter from "@ui5/logger/writers/Console"; +import {getVersion} from "./version.js"; export interface LinterArg { coverage: boolean; @@ -172,7 +173,7 @@ async function handleLint(argv: ArgumentsCamelCase) { process.stdout.write("\n"); } else if (format === "markdown") { const markdownFormatter = new Markdown(); - process.stdout.write(markdownFormatter.format(res, details)); + process.stdout.write(markdownFormatter.format(res, details, getVersion())); process.stdout.write("\n"); } else if (format === "" || format === "stylish") { const textFormatter = new Text(rootDir); diff --git a/src/cli/middlewares/logger.ts b/src/cli/middlewares/logger.ts index d910cc72..9cc11609 100644 --- a/src/cli/middlewares/logger.ts +++ b/src/cli/middlewares/logger.ts @@ -1,6 +1,6 @@ import {setLogLevel, isLogLevelEnabled, getLogger} from "@ui5/logger"; import ConsoleWriter from "@ui5/logger/writers/Console"; -import {getVersion} from "../version.js"; +import {getFormattedVersion} from "../version.js"; import type {ArgumentsCamelCase} from "yargs"; /** * Logger middleware to enable logging capabilities @@ -28,7 +28,7 @@ export async function initLogger(argv: ArgumentsCamelCase) { ConsoleWriter.init(); if (isLogLevelEnabled("verbose")) { const log = getLogger("cli:middlewares:base"); - log.verbose(`using ui5lint version ${getVersion()}`); + log.verbose(`using ui5lint version ${getFormattedVersion()}`); log.verbose(`using node version ${process.version}`); } } diff --git a/src/cli/version.ts b/src/cli/version.ts index 98d70eff..18959e9e 100644 --- a/src/cli/version.ts +++ b/src/cli/version.ts @@ -1,9 +1,14 @@ let version: string; +let formattedVersion: string; // This module holds the CLI's version information (set via cli.js) for later retrieval (e.g. from middlewares/logger) -export function setVersion(v: string) { +export function setVersionInfo(v: string, p: string) { version = v; + formattedVersion = `${v} (from ${p})`; } export function getVersion(): string { return version || ""; } +export function getFormattedVersion(): string { + return formattedVersion || ""; +} diff --git a/src/formatter/markdown.ts b/src/formatter/markdown.ts index e94b8d67..602edeb8 100644 --- a/src/formatter/markdown.ts +++ b/src/formatter/markdown.ts @@ -2,7 +2,7 @@ import {LintResult, LintMessage} from "../linter/LinterContext.js"; import {LintMessageSeverity} from "../linter/messages.js"; export class Markdown { - format(lintResults: LintResult[], showDetails: boolean): string { + format(lintResults: LintResult[], showDetails: boolean, version: string): string { let totalErrorCount = 0; let totalWarningCount = 0; let totalFatalErrorCount = 0; @@ -21,11 +21,11 @@ export class Markdown { // Add the file path as a section header findings += `### ${filePath}\n\n`; if (showDetails === true) { - findings += `| Severity | Line | Message | Details |\n`; - findings += `|----------|------|---------|---------|\n`; + findings += `| Severity | Rule | Location | Message | Details |\n`; + findings += `|----------|------|----------|---------|---------|\n`; } else { - findings += `| Severity | Line | Message |\n`; - findings += `|----------|------|---------|\n`; + findings += `| Severity | Rule | Location | Message |\n`; + findings += `|----------|------|----------|---------|\n`; } // Sort messages by severity (sorting order: fatal-errors, errors, warnings) @@ -50,6 +50,7 @@ export class Markdown { messages.forEach((msg) => { const severity = this.formatSeverity(msg.severity, msg.fatal); const location = this.formatLocation(msg.line, msg.column); + const rule = this.formatRuleId(msg.ruleId, version); let details; if (showDetails) { details = ` ${this.formatMessageDetails(msg)} |`; @@ -57,7 +58,7 @@ export class Markdown { details = ""; } - findings += `| ${severity} | \`${location}\` | ${msg.message} |${details}\n`; + findings += `| ${severity} | ${rule} | \`${location}\` | ${msg.message} |${details}\n`; }); findings += "\n"; @@ -113,4 +114,9 @@ ${findings}`; // Replace multiple spaces or newlines with a single space for clean output return `${msg.messageDetails.replace(/\s\s+|\n/g, " ")}`; } + + // Formats the rule of the lint message (ruleId and link to rules.md) + private formatRuleId(ruleId: string, version: string): string { + return `[${ruleId}](https://github.com/SAP/ui5-linter/blob/v${version}/docs/Rules.md#${ruleId})`; + } } diff --git a/test/lib/cli.ts b/test/lib/cli.ts index 7f770a54..bfea0bd6 100644 --- a/test/lib/cli.ts +++ b/test/lib/cli.ts @@ -17,7 +17,8 @@ const test = anyTest as TestFn<{ argv: () => unknown; }; yargs: SinonStub; - setVersion: SinonStub; + setVersionInfo: SinonStub; + getFormattedVersion: SinonStub; cliBase: SinonStub; readdir: SinonStub; cli: MockFunction; @@ -44,13 +45,15 @@ test.beforeEach(async (t) => { t.context.yargs = sinon.stub().returns(t.context.yargsInstance).named("yargs"); - t.context.setVersion = sinon.stub().named("setVersion"); + t.context.setVersionInfo = sinon.stub().named("setVersionInfo"); + t.context.getFormattedVersion = sinon.stub().returns("1.2.3 (from /path/to/cli.js)").named("getFormattedVersion"); t.context.cliBase = sinon.stub().named("cliBase"); t.context.cli = await esmock.p("../../src/cli.js", { "yargs": t.context.yargs, "../../src/cli/version.js": { - setVersion: t.context.setVersion, + setVersionInfo: t.context.setVersionInfo, + getFormattedVersion: t.context.getFormattedVersion, }, "../../src/cli/base.js": t.context.cliBase, "module": { @@ -68,7 +71,7 @@ test.afterEach.always((t) => { test.serial("CLI", async (t) => { const { cli, argvGetter, yargsInstance, yargs, - setVersion, cliBase, + setVersionInfo, cliBase, getFormattedVersion, } = t.context; await cli("module"); @@ -81,14 +84,17 @@ test.serial("CLI", async (t) => { "parse-numbers": false, }]); - t.is(setVersion.callCount, 1); - t.deepEqual(setVersion.getCall(0).args, [ - `${pkg.version} (from ${fileURLToPath(new URL("../../bin/ui5lint.js", import.meta.url))})`, + t.is(setVersionInfo.callCount, 1); + t.deepEqual(setVersionInfo.getCall(0).args, [ + pkg.version, fileURLToPath(new URL("../../bin/ui5lint.js", import.meta.url)), ]); + t.is(getFormattedVersion.callCount, 1); + t.deepEqual(getFormattedVersion.getCall(0).args, []); + t.is(yargsInstance.version.callCount, 1); t.deepEqual(yargsInstance.version.getCall(0).args, [ - `${pkg.version} (from ${fileURLToPath(new URL("../../bin/ui5lint.js", import.meta.url))})`, + getFormattedVersion.getCall(0).returnValue, ]); t.is(yargsInstance.scriptName.callCount, 1); @@ -111,7 +117,7 @@ test.serial("CLI", async (t) => { sinon.assert.callOrder( yargs, yargsInstance.parserConfiguration, - setVersion, + setVersionInfo, yargsInstance.version, yargsInstance.scriptName, cliBase, diff --git a/test/lib/cli/middlewares/logger.ts b/test/lib/cli/middlewares/logger.ts index b7928bb8..a68bcb18 100644 --- a/test/lib/cli/middlewares/logger.ts +++ b/test/lib/cli/middlewares/logger.ts @@ -6,7 +6,7 @@ const test = anyTest as TestFn<{ verboseLogStub: SinonStub; setLogLevelStub: SinonStub; isLogLevelEnabledStub: SinonStub; - getVersionStub: SinonStub; + getFormattedVersionStub: SinonStub; logger: MockFunction & { initLogger: (args: {loglevel?: string; verbose?: boolean; perf?: boolean; silent?: boolean}) => Promise | void; @@ -17,10 +17,10 @@ test.beforeEach(async (t) => { t.context.verboseLogStub = sinon.stub(); t.context.setLogLevelStub = sinon.stub(); t.context.isLogLevelEnabledStub = sinon.stub().returns(true); - t.context.getVersionStub = sinon.stub().returns("1.0.0"); + t.context.getFormattedVersionStub = sinon.stub().returns("1.0.0"); t.context.logger = await esmock("../../../../src/cli/middlewares/logger.js", { "../../../../src/cli/version.js": { - getVersion: t.context.getVersionStub, + getFormattedVersion: t.context.getFormattedVersionStub, }, "@ui5/logger": { getLogger: () => ({ @@ -33,13 +33,13 @@ test.beforeEach(async (t) => { }); test.serial("init logger", async (t) => { - const {logger, setLogLevelStub, isLogLevelEnabledStub, verboseLogStub, getVersionStub} = t.context; + const {logger, setLogLevelStub, isLogLevelEnabledStub, verboseLogStub, getFormattedVersionStub} = t.context; await logger.initLogger({}); t.is(setLogLevelStub.callCount, 0, "setLevel has not been called"); t.is(isLogLevelEnabledStub.callCount, 1, "isLogLevelEnabled has been called once"); t.is(isLogLevelEnabledStub.firstCall.firstArg, "verbose", "isLogLevelEnabled has been called with expected argument"); - t.is(getVersionStub.callCount, 1, "getVersion has been called once"); + t.is(getFormattedVersionStub.callCount, 1, "getFormattedVersion has been called once"); t.is(verboseLogStub.callCount, 2, "log.verbose has been called twice"); t.is(verboseLogStub.firstCall.firstArg, "using ui5lint version 1.0.0", "log.verbose has been called with expected argument on first call"); diff --git a/test/lib/cli/version.ts b/test/lib/cli/version.ts index 0a5c723c..f141c7c1 100644 --- a/test/lib/cli/version.ts +++ b/test/lib/cli/version.ts @@ -1,12 +1,19 @@ import test from "ava"; -import {setVersion, getVersion} from "../../../src/cli/version.js"; +import {setVersionInfo, getFormattedVersion, getVersion} from "../../../src/cli/version.js"; test("Set and get version", (t) => { + const sampleVersion = "1.2.3"; + const sampleVersion2 = "4.5.6-foo.bar"; + const samplePath = "/path/to/cli.js"; + + t.is(getFormattedVersion(), ""); t.is(getVersion(), ""); - setVersion("1.2.3"); - t.is(getVersion(), "1.2.3"); + setVersionInfo(sampleVersion, samplePath); + t.is(getFormattedVersion(), `${sampleVersion} (from ${samplePath})`); + t.is(getVersion(), sampleVersion); - setVersion("4.5.6-foo.bar"); - t.is(getVersion(), "4.5.6-foo.bar"); + setVersionInfo(sampleVersion2, samplePath); + t.is(getFormattedVersion(), `${sampleVersion2} (from ${samplePath})`); + t.is(getVersion(), sampleVersion2); }); diff --git a/test/lib/formatter/markdown.ts b/test/lib/formatter/markdown.ts index 3966ffc0..98fc42f7 100644 --- a/test/lib/formatter/markdown.ts +++ b/test/lib/formatter/markdown.ts @@ -92,7 +92,7 @@ test("Default", (t) => { const {lintResults} = t.context; const markdownFormatter = new Markdown(); - const markdownResult = markdownFormatter.format(lintResults, false); + const markdownResult = markdownFormatter.format(lintResults, false, "1.2.3"); t.snapshot(markdownResult); }); @@ -101,14 +101,14 @@ test("Details", (t) => { const {lintResults} = t.context; const markdownFormatter = new Markdown(); - const markdownResult = markdownFormatter.format(lintResults, true); + const markdownResult = markdownFormatter.format(lintResults, true, "1.2.3"); t.snapshot(markdownResult); }); test("No findings", (t) => { const markdownFormatter = new Markdown(); - const markdownResult = markdownFormatter.format([], true); + const markdownResult = markdownFormatter.format([], true, "1.2.3"); t.snapshot(markdownResult); }); diff --git a/test/lib/formatter/snapshots/markdown.ts.md b/test/lib/formatter/snapshots/markdown.ts.md index beb8e826..6856a480 100644 --- a/test/lib/formatter/snapshots/markdown.ts.md +++ b/test/lib/formatter/snapshots/markdown.ts.md @@ -17,20 +17,20 @@ Generated by [AVA](https://avajs.dev). ## Findings␊ ### webapp/Component.js␊ ␊ - | Severity | Line | Message |␊ - |----------|------|---------|␊ - | Error | \`1:1\` | Error message |␊ - | Warning | \`2:2\` | Warning message |␊ + | Severity | Rule | Location | Message |␊ + |----------|------|----------|---------|␊ + | Error | [rule1](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule1) | \`1:1\` | Error message |␊ + | Warning | [rule2](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule2) | \`2:2\` | Warning message |␊ ␊ ### webapp/Main.controller.js␊ ␊ - | Severity | Line | Message |␊ - |----------|------|---------|␊ - | Fatal Error | \`3:6\` | Another error message |␊ - | Fatal Error | \`12:3\` | Another error message |␊ - | Error | \`11:2\` | Another error message |␊ - | Error | \`11:3\` | Another error message |␊ - | Warning | \`12:3\` | Another error message |␊ + | Severity | Rule | Location | Message |␊ + |----------|------|----------|---------|␊ + | Fatal Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`3:6\` | Another error message |␊ + | Fatal Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`12:3\` | Another error message |␊ + | Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`11:2\` | Another error message |␊ + | Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`11:3\` | Another error message |␊ + | Warning | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`12:3\` | Another error message |␊ ␊ **Note:** Use \`ui5lint --details\` to show more information about the findings.␊ ` @@ -48,20 +48,20 @@ Generated by [AVA](https://avajs.dev). ## Findings␊ ### webapp/Component.js␊ ␊ - | Severity | Line | Message | Details |␊ - |----------|------|---------|---------|␊ - | Error | \`1:1\` | Error message | Message details |␊ - | Warning | \`2:2\` | Warning message | Message details |␊ + | Severity | Rule | Location | Message | Details |␊ + |----------|------|----------|---------|---------|␊ + | Error | [rule1](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule1) | \`1:1\` | Error message | Message details |␊ + | Warning | [rule2](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule2) | \`2:2\` | Warning message | Message details |␊ ␊ ### webapp/Main.controller.js␊ ␊ - | Severity | Line | Message | Details |␊ - |----------|------|---------|---------|␊ - | Fatal Error | \`3:6\` | Another error message | Message details |␊ - | Fatal Error | \`12:3\` | Another error message | Message details |␊ - | Error | \`11:2\` | Another error message | Message details |␊ - | Error | \`11:3\` | Another error message | Message details |␊ - | Warning | \`12:3\` | Another error message | Message details |␊ + | Severity | Rule | Location | Message | Details |␊ + |----------|------|----------|---------|---------|␊ + | Fatal Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`3:6\` | Another error message | Message details |␊ + | Fatal Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`12:3\` | Another error message | Message details |␊ + | Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`11:2\` | Another error message | Message details |␊ + | Error | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`11:3\` | Another error message | Message details |␊ + | Warning | [rule3](https://github.com/SAP/ui5-linter/blob/v1.2.3/docs/Rules.md#rule3) | \`12:3\` | Another error message | Message details |␊ ␊ ` diff --git a/test/lib/formatter/snapshots/markdown.ts.snap b/test/lib/formatter/snapshots/markdown.ts.snap index db098559559f0c07172d6311be8c58058c43f51e..720e7936c9c03e681c07c1527fc5eb33aa09bd75 100644 GIT binary patch literal 603 zcmV-h0;K&xRzV2AyT>5s*(s zAVxSIjUS5$00000000Bkl;3LGFcikytzn?My}<$Bv}Unmn{42VLieX*(3a59oxfhgO34y4-Pjk>`M&cV>32JdxEx;T??2Em!*To? zM>OY#X+blcNTa{q#xXVY)4{LDdr$Vtwcpx%`sn9@1^stjIAg+~f=kS#GQ_f=m!~OJ zH-sF+3&@m=IHnp7yMRhbrJsQh6RHFgV|@fbj={El7*Rv{Y=>==vd$?Jak+_DmIV`x zXqLIJWSU8V!Z=?wAqDjC8Wl4)P{3u*5ehhyLu!~5P{28AO~(iYDcXxw)IRm!f)wzk zv;YNsRyjxS%VA@J9+QstlQ>Q=WfJhBf#Fz`Ze0Q2JM(ieP~CNUTEHy89PK|l0M!FlI+L z*a;w;cbe0ei-~+eM`FDbi57d-qY_N_jzYY6WhL!21DD1 zzD5}2tXo!xb~{Ex8P@|a5_BRbkV=KX#7L@idaG$9a|0$p7|oF5kR=VP(|2judRe1k z(E4v^2(z9Z@P->BHJ&hEdxAG4hm%yt%-?bI+!egkMZc5U|x002iJAoc(N literal 517 zcmV+g0{ZT*kw{b zCqwNSYvzThk~fHN-~)>IJpOp_8)jWzP^^q>0$iHyLh4v&&jT?Ys>LZ`e76w z{=T4=4p$TICT;1uadB-HL>QhLrZ@~Sc7(}7jWVSfy=W&(ds6q_CF~7#e--~fnr$y6 z8YkTklExOhV$)i@_sP4X)%3U4bX=U83YlLBc{|<& Date: Tue, 3 Dec 2024 10:25:35 +0100 Subject: [PATCH 3/3] docs: Rename PERFORMANCE.md To align with naming convention. --- docs/{PERFORMANCE.md => Performance.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{PERFORMANCE.md => Performance.md} (100%) diff --git a/docs/PERFORMANCE.md b/docs/Performance.md similarity index 100% rename from docs/PERFORMANCE.md rename to docs/Performance.md