@ui5/linter
Version:
A static code analysis tool for UI5
78 lines • 3.54 kB
JavaScript
import { deprecatedLibraries, deprecatedThemeLibraries } from "../../utils/deprecations.js";
import { fromYaml, getPosition } from "data-with-position";
import { MESSAGE } from "../messages.js";
// This regex is derived from the single-line variant defined in ui5types/directives.ts
const DIRECTIVE_REGEX = /#\s*ui5lint-(enable|disable)(?:-((?:next-)?line))?([ \t]+(?:[\w-]+[ \t]*,[ \t]*)*(?:[ \t]*[\w-]+))?[ \t]*,?[ \t]*(?:--.*)?$/mg;
export default class YamlLinter {
#content;
#resourcePath;
#context;
constructor(resourcePath, content, context) {
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 = this.#content.split(/(?:\r\n|\r|\n)---/g);
// Calculate the starting line number of each part document
let lineNumberOffset = 0;
allDocuments.forEach((document) => {
// Parse content only of the current part
const parsedYamlWithPosInfo = this.#parseYaml(document);
// Analyze part content with line number offset
this.#analyzeYaml(parsedYamlWithPosInfo, lineNumberOffset);
this.#collectDirectives(document, 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, MESSAGE.PARSING_ERROR, { message });
}
}
#parseYaml(content) {
// Create JS object from YAML content with position information
return fromYaml(content);
}
#analyzeYaml(yaml, offset) {
// Check for deprecated libraries
yaml?.framework?.libraries?.forEach((lib) => {
const libraryName = lib.name.toString();
if (deprecatedLibraries.includes(libraryName) || deprecatedThemeLibraries.includes(libraryName)) {
const positionInfo = getPosition(lib);
this.#context.addLintingMessage(this.#resourcePath, MESSAGE.DEPRECATED_LIBRARY, {
libraryName,
}, {
line: positionInfo.start.line + offset,
column: positionInfo.start.column,
});
}
});
}
#collectDirectives(content, offset) {
const matches = content.matchAll(DIRECTIVE_REGEX);
for (const match of matches) {
const action = (match[1] ?? match[4]);
const scope = (match[2] ?? match[5]);
const rules = match[3] ?? match[6];
let ruleNames = rules?.split(",") ?? [];
ruleNames = ruleNames.map((rule) => rule.trim());
// Determine line and column of match
const left = content.slice(0, match.index);
const line = (left.match(/\n/g) ?? []).length + 1 + offset;
const lastIndexOf = left.lastIndexOf("\n") + 1;
const column = match.index - lastIndexOf + 1;
this.#context.addDirective(this.#resourcePath, {
action,
scope, ruleNames,
line,
column,
});
}
}
}
//# sourceMappingURL=YamlLinter.js.map