inital upload

This commit is contained in:
jackbeeby
2025-05-15 13:35:49 +10:00
commit 8c53ff1000
9092 changed files with 1833300 additions and 0 deletions

65
node_modules/eslint/lib/services/parser-service.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
/**
* @fileoverview ESLint Parser
* @author Nicholas C. Zakas
*/
/* eslint class-methods-use-this: off -- Anticipate future constructor arguments. */
"use strict";
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
/** @typedef {import("../linter/vfile.js").VFile} VFile */
/** @typedef {import("@eslint/core").Language} Language */
/** @typedef {import("@eslint/core").LanguageOptions} LanguageOptions */
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* The parser for ESLint.
*/
class ParserService {
/**
* Parses the given file synchronously.
* @param {VFile} file The file to parse.
* @param {{language:Language,languageOptions:LanguageOptions}} config The configuration to use.
* @returns {Object} An object with the parsed source code or errors.
* @throws {Error} If the parser returns a promise.
*/
parseSync(file, config) {
const { language, languageOptions } = config;
const result = language.parse(file, { languageOptions });
if (typeof result.then === "function") {
throw new Error("Unsupported: Language parser returned a promise.");
}
if (result.ok) {
return {
ok: true,
sourceCode: language.createSourceCode(file, result, {
languageOptions,
}),
};
}
// if we made it to here there was an error
return {
ok: false,
errors: result.errors.map(error => ({
ruleId: null,
nodeType: null,
fatal: true,
severity: 2,
message: `Parsing error: ${error.message}`,
line: error.line,
column: error.column,
})),
};
}
}
module.exports = { ParserService };

101
node_modules/eslint/lib/services/processor-service.js generated vendored Normal file
View File

@@ -0,0 +1,101 @@
/**
* @fileoverview ESLint Processor Service
* @author Nicholas C. Zakas
*/
/* eslint class-methods-use-this: off -- Anticipate future constructor arguments. */
"use strict";
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
const path = require("node:path");
const { VFile } = require("../linter/vfile.js");
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
/** @typedef {import("../shared/types.js").LintMessage} LintMessage */
/** @typedef {import("../linter/vfile.js").VFile} VFile */
/** @typedef {import("@eslint/core").Language} Language */
/** @typedef {import("eslint").Linter.Processor} Processor */
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* The service that applies processors to files.
*/
class ProcessorService {
/**
* Preprocesses the given file synchronously.
* @param {VFile} file The file to preprocess.
* @param {{processor:Processor}} config The configuration to use.
* @returns {{ok:boolean, files?: Array<VFile>, errors?: Array<LintMessage>}} An array of preprocessed files or errors.
* @throws {Error} If the preprocessor returns a promise.
*/
preprocessSync(file, config) {
const { processor } = config;
let blocks;
try {
blocks = processor.preprocess(file.rawBody, file.path);
} catch (ex) {
// If the message includes a leading line number, strip it:
const message = `Preprocessing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
return {
ok: false,
errors: [
{
ruleId: null,
fatal: true,
severity: 2,
message,
line: ex.lineNumber,
column: ex.column,
nodeType: null,
},
],
};
}
if (typeof blocks.then === "function") {
throw new Error("Unsupported: Preprocessor returned a promise.");
}
return {
ok: true,
files: blocks.map((block, i) => {
// Legacy behavior: return the block as a string
if (typeof block === "string") {
return block;
}
const filePath = path.join(file.path, `${i}_${block.filename}`);
return new VFile(filePath, block.text, {
physicalPath: file.physicalPath,
});
}),
};
}
/**
* Postprocesses the given messages synchronously.
* @param {VFile} file The file to postprocess.
* @param {LintMessage[][]} messages The messages to postprocess.
* @param {{processor:Processor}} config The configuration to use.
* @returns {LintMessage[]} The postprocessed messages.
*/
postprocessSync(file, messages, config) {
const { processor } = config;
return processor.postprocess(messages, file.path);
}
}
module.exports = { ProcessorService };

View File

@@ -0,0 +1,289 @@
/**
* @fileoverview Manages the suppressed violations.
* @author Iacovos Constantinou
*/
"use strict";
//-----------------------------------------------------------------------------
// Requirements
//-----------------------------------------------------------------------------
const fs = require("node:fs");
const path = require("node:path");
const { calculateStatsPerFile } = require("../eslint/eslint-helpers");
//------------------------------------------------------------------------------
// Typedefs
//------------------------------------------------------------------------------
// For VSCode IntelliSense
/** @typedef {import("../shared/types").LintResult} LintResult */
/** @typedef {import("../shared/types").SuppressedViolations} SuppressedViolations */
//-----------------------------------------------------------------------------
// Exports
//-----------------------------------------------------------------------------
/**
* Manages the suppressed violations.
*/
class SuppressionsService {
filePath = "";
cwd = "";
/**
* Creates a new instance of SuppressionsService.
* @param {Object} options The options.
* @param {string} [options.filePath] The location of the suppressions file.
* @param {string} [options.cwd] The current working directory.
*/
constructor({ filePath, cwd }) {
this.filePath = filePath;
this.cwd = cwd;
}
/**
* Updates the suppressions file based on the current violations and the provided rules.
* If no rules are provided, all violations are suppressed.
* @param {LintResult[]|undefined} results The lint results.
* @param {string[]|undefined} rules The rules to suppress.
* @returns {Promise<void>}
*/
async suppress(results, rules) {
const suppressions = await this.load();
for (const result of results) {
const relativeFilePath = this.getRelativeFilePath(result.filePath);
const violationsByRule = SuppressionsService.countViolationsByRule(
result.messages,
);
for (const ruleId in violationsByRule) {
if (rules && !rules.includes(ruleId)) {
continue;
}
suppressions[relativeFilePath] ??= {};
suppressions[relativeFilePath][ruleId] =
violationsByRule[ruleId];
}
}
return this.save(suppressions);
}
/**
* Removes old, unused suppressions for violations that do not occur anymore.
* @param {LintResult[]} results The lint results.
* @returns {Promise<void>} No return value.
*/
async prune(results) {
const suppressions = await this.load();
const { unused } = this.applySuppressions(results, suppressions);
for (const file in unused) {
if (!suppressions[file]) {
continue;
}
for (const rule in unused[file]) {
if (!suppressions[file][rule]) {
continue;
}
const suppressionsCount = suppressions[file][rule].count;
const violationsCount = unused[file][rule].count;
if (suppressionsCount === violationsCount) {
// Remove unused rules
delete suppressions[file][rule];
} else {
// Update the count to match the new number of violations
suppressions[file][rule].count -= violationsCount;
}
}
// Cleanup files with no rules
if (Object.keys(suppressions[file]).length === 0) {
delete suppressions[file];
}
}
return this.save(suppressions);
}
/**
* Checks the provided suppressions against the lint results.
*
* For each file, counts the number of violations per rule.
* For each rule in each file, compares the number of violations against the counter from the suppressions file.
* If the number of violations is less or equal to the counter, messages are moved to `LintResult#suppressedMessages` and ignored.
* Otherwise, all violations are reported as usual.
* @param {LintResult[]} results The lint results.
* @param {SuppressedViolations} suppressions The suppressions.
* @returns {{
* results: LintResult[],
* unused: SuppressedViolations
* }} The updated results and the unused suppressions.
*/
applySuppressions(results, suppressions) {
/**
* We copy the results to avoid modifying the original objects
* We remove only result messages that are matched and hence suppressed
* We leave the rest untouched to minimize the risk of losing parts of the original data
*/
const filtered = structuredClone(results);
const unused = {};
for (const result of filtered) {
const relativeFilePath = this.getRelativeFilePath(result.filePath);
if (!suppressions[relativeFilePath]) {
continue;
}
const violationsByRule = SuppressionsService.countViolationsByRule(
result.messages,
);
let wasSuppressed = false;
for (const ruleId in violationsByRule) {
if (!suppressions[relativeFilePath][ruleId]) {
continue;
}
const suppressionsCount =
suppressions[relativeFilePath][ruleId].count;
const violationsCount = violationsByRule[ruleId].count;
// Suppress messages if the number of violations is less or equal to the suppressions count
if (violationsCount <= suppressionsCount) {
SuppressionsService.suppressMessagesByRule(result, ruleId);
wasSuppressed = true;
}
// Update the count to match the new number of violations, otherwise remove the rule entirely
if (violationsCount < suppressionsCount) {
unused[relativeFilePath] ??= {};
unused[relativeFilePath][ruleId] ??= {};
unused[relativeFilePath][ruleId].count =
suppressionsCount - violationsCount;
}
}
// Mark as unused all the suppressions that were not matched against a rule
for (const ruleId in suppressions[relativeFilePath]) {
if (violationsByRule[ruleId]) {
continue;
}
unused[relativeFilePath] ??= {};
unused[relativeFilePath][ruleId] =
suppressions[relativeFilePath][ruleId];
}
// Recalculate stats if messages were suppressed
if (wasSuppressed) {
Object.assign(result, calculateStatsPerFile(result.messages));
}
}
return {
results: filtered,
unused,
};
}
/**
* Loads the suppressions file.
* @throws {Error} If the suppressions file cannot be parsed.
* @returns {Promise<SuppressedViolations>} The suppressions.
*/
async load() {
try {
const data = await fs.promises.readFile(this.filePath, "utf8");
return JSON.parse(data);
} catch (err) {
if (err.code === "ENOENT") {
return {};
}
throw new Error(
`Failed to parse suppressions file at ${this.filePath}`,
);
}
}
/**
* Updates the suppressions file.
* @param {SuppressedViolations} suppressions The suppressions to save.
* @returns {Promise<void>}
* @private
*/
save(suppressions) {
return fs.promises.writeFile(
this.filePath,
JSON.stringify(suppressions, null, 2),
);
}
/**
* Counts the violations by rule, ignoring warnings.
* @param {LintMessage[]} messages The messages to count.
* @returns {Record<string, number>} The number of violations by rule.
*/
static countViolationsByRule(messages) {
return messages.reduce((totals, message) => {
if (message.severity === 2 && message.ruleId) {
totals[message.ruleId] ??= { count: 0 };
totals[message.ruleId].count++;
}
return totals;
}, {});
}
/**
* Returns the relative path of a file to the current working directory.
* Always in POSIX format for consistency and interoperability.
* @param {string} filePath The file path.
* @returns {string} The relative file path.
*/
getRelativeFilePath(filePath) {
return path
.relative(this.cwd, filePath)
.split(path.sep)
.join(path.posix.sep);
}
/**
* Moves the messages matching the rule to `LintResult#suppressedMessages` and updates the stats.
* @param {LintResult} result The result to update.
* @param {string} ruleId The rule to suppress.
* @returns {void}
*/
static suppressMessagesByRule(result, ruleId) {
const suppressedMessages = result.messages.filter(
message => message.ruleId === ruleId,
);
result.suppressedMessages = result.suppressedMessages.concat(
suppressedMessages.map(message => {
message.suppressions = [
{
kind: "file",
justification: "",
},
];
return message;
}),
);
result.messages = result.messages.filter(
message => message.ruleId !== ruleId,
);
}
}
module.exports = { SuppressionsService };