diff --git a/src/linter/yaml/YamlLinter.ts b/src/linter/yaml/YamlLinter.ts index cc8fbba2d..70e3b5295 100644 --- a/src/linter/yaml/YamlLinter.ts +++ b/src/linter/yaml/YamlLinter.ts @@ -35,19 +35,24 @@ export default class YamlLinter { // eslint-disable-next-line @typescript-eslint/require-await async lint() { try { - // TODO: Support multiple documents in one Yaml file - // https://sap.github.io/ui5-tooling/stable/pages/extensibility/CustomTasks/#example-custom-task-extension-defined-in-ui5-project - // How: Loop through this.#content for each line - // Check if line matches yamlDocumentSeparator ('---') - // Use index of line as offset - // Call analyzeYaml() and Pass offset + /* Support multiple documents in one Yaml file + https://sap.github.io/ui5-tooling/stable/pages/extensibility/CustomTasks/#example-custom-task-extension-defined-in-ui5-project */ - // const yamlDocumentLines = this.#content.split(/\r?\n|\r|\n/g); // End of line regex - this.#content.split("---").forEach((partDocument) => { - // TODO: Calculate offset + Pass to analyzeYaml() - const source: YamlContent = this.#parseYaml(partDocument); - this.#analyzeYaml(source); - }); + // Split Yaml file into part documents by '---' separator + const partDocuments = this.#content.split(/(\r?\n|\r|\n)---/g).map((part) => part.trim()); + + // Calculate the starting line number of each part document + let lineNumberOffset = 0; + for (const part of partDocuments) { + if (part !== "") { + // Parse content only of the current part + const parsedYamlWithPosInfo: YamlContent = this.#parseYaml(part); + // Analyze part content with line number offset + this.#analyzeYaml(parsedYamlWithPosInfo, lineNumberOffset); + // Update line number offset for next part + lineNumberOffset += part.split(/\r?\n|\r|\n/g).length; + } + } } catch (err) { const message = err instanceof Error ? err.message : String(err); this.#context.addLintingMessage(this.#resourcePath, { @@ -64,17 +69,16 @@ export default class YamlLinter { return fromYaml(fileContent) as YamlContent; } - #analyzeYaml(yamlObject: YamlContent) { + #analyzeYaml(yamlObject: YamlContent, offset: number) { // Check for deprecated libraries yamlObject?.framework?.libraries?.forEach((lib) => { if (deprecatedLibraries.includes(lib.name.toString())) { const positionInfo = getPosition(lib); - // TODO: Add offset to line property (addition) this.#context.addLintingMessage(this.#resourcePath, { ruleId: "ui5-linter-no-deprecated-api", severity: LintMessageSeverity.Error, fatal: undefined, - line: positionInfo.start.line, + line: positionInfo.start.line + offset, column: positionInfo.start.column, message: `Use of deprecated library '${lib.name}'`, }); diff --git a/test/lib/linter/YamlLinter.ts b/test/lib/linter/YamlLinter.ts index 5e3b0ddf9..b9c2c85e0 100644 --- a/test/lib/linter/YamlLinter.ts +++ b/test/lib/linter/YamlLinter.ts @@ -51,13 +51,14 @@ framework: t.is(messages[2].line, 11, `Line is correct`); }); -test.only("Test YamlLinter report (parsing and analyzing) with multiple documents", async (t) => { - /* Mock resource content of ui5.yaml file, +test("Test YamlLinter report (parsing and analyzing) with multiple documents", async (t) => { + /* Mock resource content of ui5.yaml file with multiple documents, (formatted as used in src/linter/yaml/linter.ts) (contains relevant 'framework' property and 'libraries' sub-property), - (contains only deprecated libraries) */ + (contains only deprecated libraries) + (contains document separators ('---') + comments after separator) */ const resourceContent = -`--- # Task extension as part of your project +`--- # This is the first document part specVersion: "3.2" kind: extension type: task @@ -65,7 +66,7 @@ metadata: name: render-markdown-files task: path: lib/tasks/renderMarkdownFiles.js ---- # This is a comment +--- # This is the second document part specVersion: '3.0' metadata: name: ava-test-ui5yamllinter @@ -76,7 +77,15 @@ framework: libraries: - name: sap.ca.scfld.md - name: sap.ca.ui - - name: sap.fe.common`; + - name: sap.fe.common +--- # This is the third document part +specVersion: "3.2" +kind: extension +type: task +metadata: + name: render-markdown-files +task: + path: lib/tasks/renderMarkdownFiles.js`; const resourcePath = "/ui5.yaml"; const projectPath = "test.yamllinter"; @@ -94,6 +103,35 @@ framework: // Test each message t.is(messages[0].ruleId, "ui5-linter-no-deprecated-api", `RuleId is correct`); + t.is(messages[0].message, `Use of deprecated library 'sap.ca.scfld.md'`, `Message is correct`); + t.is(messages[0].column, 7, `Column is correct`); + t.is(messages[0].line, 18, `Line is correct`); + + t.is(messages[1].ruleId, "ui5-linter-no-deprecated-api", `RuleId is correct`); + t.is(messages[1].message, `Use of deprecated library 'sap.ca.ui'`, `Message is correct`); + t.is(messages[1].column, 7, `Column is correct`); + t.is(messages[1].line, 19, `Line is correct`); - // TODO: Add tests for position info of messages (lines, columns) + t.is(messages[2].ruleId, "ui5-linter-no-deprecated-api", `RuleId is correct`); + t.is(messages[2].message, `Use of deprecated library 'sap.fe.common'`, `Message is correct`); + t.is(messages[2].column, 7, `Column is correct`); + t.is(messages[2].line, 20, `Line is correct`); +}); + +test("Test YamlLinter report with empty ui5.yaml", async (t) => { + const resourceContent = ``; + + const resourcePath = "/ui5.yaml"; + const projectPath = "test.yamllinter"; + const context = new LinterContext({rootDir: projectPath}); + + // Create UI5YamlLinter instance with resource content + const linter = new YamlLinter(resourcePath, resourceContent, context); + // Run UI5YamlLinter report + await linter.lint(); + + const messages = context.getLintingMessages("/ui5.yaml"); + + // Test returned messages + t.is(messages.length, 0, "0 messages should be reported"); });