generated from SAP/repository-template
-
Notifications
You must be signed in to change notification settings - Fork 4
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: Add detection for deprecated dependencies in .library #104
Merged
maxreichmann
merged 27 commits into
main
from
feature-825-analyze-library.js-&-.library
Jul 30, 2024
Merged
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
9c019b0
feat: Add Linter for .library files
maxreichmann a05bdfe
feat: Add xml parser
maxreichmann 430ac47
fix: Eslint issues
d3xter666 e7a0bba
fix: Remove eslint annotations
d3xter666 d78f1a7
feat: Detect depr. libs within .library files
maxreichmann 8b262ac
refactor: Rename variables
maxreichmann f2e1065
fix: Eslint issues
d3xter666 da44641
test: Update snapshots
d3xter666 610302f
fix: Eslint issues
d3xter666 ca7a962
fix: Remove debug leftover
maxreichmann e9bd8af
test: Add test for xmlParser
maxreichmann 2a6533d
fix: Adjust test for xmlParser
maxreichmann 442ae21
refactor: Clean up
maxreichmann ce5dd32
test: Update snapshots
maxreichmann 8f7284a
refactor: Use util consts in linter messages
maxreichmann a6c2dac
refactor: Use util const
maxreichmann a876b14
fix: Use workspace reader instead of the rootReader
d3xter666 0f86b32
fix: Check for empty textNodes within libraryName tag
d3xter666 40af990
refactor: Extend xmlParser to support also openTags
d3xter666 12bfaec
refactor: Detect libs only when positioned correctly within .library …
d3xter666 d601d26
fix: Correct Glob pattern for .library files
d3xter666 6d9f896
test: Add test for the additional cases
d3xter666 e64b03a
test: Update snapshots
d3xter666 9dc5ccc
refactor: Provide correct ruleId
d3xter666 e78d5d4
refactor: Remove trim from the check
d3xter666 c76dce5
refactor: Remove empty lib check
d3xter666 3971889
refactor: Remove slicing from stack check
d3xter666 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import {LintMessageSeverity} from "../LinterContext.js"; | ||
import LinterContext from "../LinterContext.js"; | ||
import {deprecatedLibraries} from "../../utils/deprecations.js"; | ||
import {SaxEventType, Tag as SaxTag} from "sax-wasm"; | ||
import {parseXML} from "../../utils/xmlParser.js"; | ||
import {ReadStream} from "node:fs"; | ||
import {RULES, MESSAGES, formatMessage} from "../linterReporting.js"; | ||
|
||
export default class DotLibraryLinter { | ||
#contentStream; | ||
#resourcePath; | ||
#context: LinterContext; | ||
|
||
constructor(resourcePath: string, contentStream: ReadStream, context: LinterContext) { | ||
this.#contentStream = contentStream; | ||
this.#resourcePath = resourcePath; | ||
this.#context = context; | ||
} | ||
|
||
async lint() { | ||
try { | ||
const dotLibraryDependencyTags = await this.#parseDotLibrary(this.#contentStream); | ||
this.#analyzeDeprecatedLibs(dotLibraryDependencyTags); | ||
} catch (err) { | ||
const message = err instanceof Error ? err.message : String(err); | ||
this.#context.addLintingMessage(this.#resourcePath, { | ||
severity: LintMessageSeverity.Error, | ||
message, | ||
ruleId: RULES["ui5-linter-parsing-error"], | ||
fatal: true, | ||
}); | ||
} | ||
} | ||
|
||
async #parseDotLibrary(contentStream: ReadStream): Promise<SaxTag[]> { | ||
const libs = new Set(); | ||
await parseXML(contentStream, (event, tag) => { | ||
if (tag instanceof SaxTag && | ||
event === SaxEventType.CloseTag && | ||
tag.value === "libraryName") { | ||
libs.add(tag); | ||
} | ||
}); | ||
|
||
return Array.from(libs) as SaxTag[]; | ||
} | ||
|
||
#analyzeDeprecatedLibs(libs: SaxTag[]) { | ||
// Check for deprecated libraries | ||
libs.forEach((lib) => { | ||
const libName = lib.textNodes[0].value; | ||
const {line, character: column} = lib.openStart; | ||
|
||
if (deprecatedLibraries.includes(libName)) { | ||
this.#context.addLintingMessage(this.#resourcePath, { | ||
ruleId: RULES["ui5-linter-no-deprecated-api"], | ||
d3xter666 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
severity: LintMessageSeverity.Error, | ||
fatal: undefined, | ||
line: line + 1, | ||
column: column + 1, | ||
message: formatMessage(MESSAGES.SHORT__DEPRECATED_LIBRARY, libName), | ||
}); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import {LinterParameters} from "../LinterContext.js"; | ||
import DotLibraryLinter from "./DotLibraryLinter.js"; | ||
import {Resource} from "@ui5/fs"; | ||
|
||
export default async function lintDotLibrary({context}: LinterParameters) { | ||
let dotLibraryResources: Resource[]; | ||
const pathsToLint = context.getPathsToLint(); | ||
const reader = context.getRootReader(); | ||
d3xter666 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (pathsToLint?.length) { | ||
dotLibraryResources = []; | ||
await Promise.all(pathsToLint.map(async (resourcePath) => { | ||
if (!resourcePath.endsWith(".library")) { | ||
return; | ||
} | ||
const resource = await reader.byPath(resourcePath); | ||
if (!resource) { | ||
throw new Error(`Resource not found: ${resourcePath}`); | ||
} | ||
dotLibraryResources.push(resource); | ||
})); | ||
} else { | ||
dotLibraryResources = await reader.byGlob("/src/**/.library"); | ||
} | ||
|
||
await Promise.all(dotLibraryResources.map(async (resource: Resource) => { | ||
const linter = new DotLibraryLinter(resource.getPath(), resource.getStream(), context); | ||
await linter.lint(); | ||
})); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import type {ReadStream} from "node:fs"; | ||
import {Detail, SaxEventType, SAXParser} from "sax-wasm"; | ||
import {finished} from "node:stream/promises"; | ||
import fs from "node:fs/promises"; | ||
import {createRequire} from "node:module"; | ||
const require = createRequire(import.meta.url); | ||
|
||
let saxWasmBuffer: Buffer; | ||
async function initSaxWasm() { | ||
if (!saxWasmBuffer) { | ||
const saxPath = require.resolve("sax-wasm/lib/sax-wasm.wasm"); | ||
saxWasmBuffer = await fs.readFile(saxPath); | ||
} | ||
|
||
return saxWasmBuffer; | ||
} | ||
|
||
export async function parseXML(contentStream: ReadStream, parseHandler: (type: SaxEventType, tag: Detail) => void) { | ||
const options = {highWaterMark: 32 * 1024}; // 32k chunks | ||
const saxWasmBuffer = await initSaxWasm(); | ||
const saxParser = new SAXParser(SaxEventType.CloseTag, options); | ||
|
||
saxParser.eventHandler = parseHandler; | ||
|
||
// Instantiate and prepare the wasm for parsing | ||
if (!await saxParser.prepareWasm(saxWasmBuffer)) { | ||
throw new Error("Unknown error during WASM Initialization"); | ||
} | ||
|
||
// stream from a file in the current directory | ||
contentStream.on("data", (chunk: Uint8Array) => { | ||
try { | ||
saxParser.write(chunk); | ||
} catch (err) { | ||
if (err instanceof Error) { | ||
// In case of an error, destroy the content stream to make the | ||
// error bubble up to our callers | ||
contentStream.destroy(err); | ||
} else { | ||
throw err; | ||
} | ||
} | ||
}); | ||
await finished(contentStream); | ||
saxParser.end(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import test from "ava"; | ||
import {parseXML} from "../../../src/utils/xmlParser.js"; | ||
import {ReadStream} from "node:fs"; | ||
import {Readable} from "node:stream"; | ||
import {SaxEventType, Tag as SaxTag} from "sax-wasm"; | ||
|
||
test("Test xmlParser with .library", async (t) => { | ||
const sampleDotLibrary = `<?xml version="1.0" ?> | ||
<library xmlns="http://www.sap.com/sap.ui.library.xsd"> | ||
<name>library.with.custom.paths</name> | ||
<vendor>SAP SE</vendor> | ||
<version>1.0</version> | ||
<copyright>any</copyright> | ||
<dependencies> | ||
<dependency> | ||
<libraryName>sap.ui.core</libraryName> | ||
</dependency> | ||
<dependency> | ||
<libraryName>sap.ca.scfld.md</libraryName> | ||
</dependency> | ||
<dependency> | ||
<libraryName>sap.ca.scfld.md</libraryName> | ||
</dependency> | ||
<dependency> | ||
<libraryName>sap.ca.ui</libraryName> | ||
</dependency> | ||
</dependencies> | ||
</library>`; | ||
|
||
// Convert raw .library content into stream | ||
const contentStream = new Readable() as ReadStream; | ||
// eslint-disable-next-line @typescript-eslint/no-empty-function | ||
contentStream._read = () => {}; | ||
contentStream.push(sampleDotLibrary); | ||
contentStream.push(null); | ||
|
||
// Call SAXParser with the contentStream | ||
const libs: SaxTag[] = []; | ||
await parseXML(contentStream, (event, tag) => { | ||
if (tag instanceof SaxTag && | ||
event === SaxEventType.CloseTag && | ||
tag.value === "libraryName") { | ||
libs.push(tag); | ||
} | ||
}); | ||
|
||
// Test parsed results | ||
t.is(libs.length, 4, "Parsed .library XML should contain 4 libraries"); | ||
t.is(libs[0].textNodes[0].value, "sap.ui.core", "First library should be 'sap.ui.core'"); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not covered by unit tests