eslint-plugin-sonarjs
Version:
SonarJS rules for ESLint
154 lines (153 loc) • 5.79 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getManifests = exports.PACKAGE_JSON = void 0;
exports.getAllDependencies = getAllDependencies;
exports.getDependencies = getDependencies;
exports.clearDependenciesCache = clearDependenciesCache;
exports.getDependenciesFromPackageJson = getDependenciesFromPackageJson;
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
const posix_1 = __importDefault(require("path/posix"));
const files_js_1 = require("./files.js");
const minimatch_1 = require("minimatch");
const find_up_js_1 = require("./find-up.js");
const fs_1 = __importDefault(require("fs"));
exports.PACKAGE_JSON = 'package.json';
/**
* The {@link FindUp} instance dedicated to retrieving `package.json` files
*/
const findPackageJsons = (0, find_up_js_1.createFindUp)(exports.PACKAGE_JSON);
const DefinitelyTyped = '@types/';
/**
* Cache for the available dependencies by dirname.
*/
const cache = new Map();
/**
* Returns the dependencies of the root package.json file collected in the cache.
* As the cache is populated lazily, it could be null in case no rule execution has touched it.
* This removes duplicate dependencies and keeps the last occurrence.
*/
function getAllDependencies() {
const dependencies = [...cache.values()]
.flatMap(dependencies => [...dependencies])
.filter((dependency) => typeof dependency.name === 'string');
return Object.values(dependencies.reduce((result, dependency) => ({
...result,
[dependency.name]: dependency,
}), {}));
}
/**
* Retrieve the dependencies of all the package.json files available for the given file.
*
* @param filename context.filename
* @param cwd working dir, will search up to that root
* @returns
*/
function getDependencies(filename, cwd) {
const dirname = posix_1.default.dirname((0, files_js_1.toUnixPath)(filename));
const cached = cache.get(dirname);
if (cached) {
return new Set([...cached].map(item => item.name));
}
const result = new Set();
cache.set(dirname, result);
(0, exports.getManifests)(dirname, cwd, fs_1.default).forEach(manifest => {
const manifestDependencies = getDependenciesFromPackageJson(manifest);
manifestDependencies.forEach(dependency => {
result.add(dependency);
});
});
return new Set([...result].map(item => item.name));
}
/**
* In the case of SonarIDE, when a package.json file changes, the cache can become obsolete.
*/
function clearDependenciesCache() {
console.debug('Clearing dependencies cache');
cache.clear();
}
function getDependenciesFromPackageJson(content) {
const result = new Set();
if (content.name) {
addDependencies(result, { [content.name]: '*' });
}
if (content.dependencies !== undefined) {
addDependencies(result, content.dependencies);
}
if (content.devDependencies !== undefined) {
addDependencies(result, content.devDependencies);
}
if (content.peerDependencies !== undefined) {
addDependencies(result, content.peerDependencies);
}
if (content.optionalDependencies !== undefined) {
addDependencies(result, content.optionalDependencies);
}
if (content._moduleAliases !== undefined) {
addDependencies(result, content._moduleAliases);
}
if (Array.isArray(content.workspaces)) {
addDependenciesArray(result, content.workspaces);
}
else if (content.workspaces?.packages) {
addDependenciesArray(result, content.workspaces?.packages);
}
return result;
}
function addDependencies(result, dependencies, isGlob = false) {
Object.keys(dependencies).forEach(name => addDependency(result, name, isGlob, dependencies[name]));
}
function addDependenciesArray(result, dependencies, isGlob = true) {
dependencies.forEach(name => addDependency(result, name, isGlob));
}
function addDependency(result, dependency, isGlob, version) {
if (isGlob) {
result.add({
name: new minimatch_1.Minimatch(dependency, { nocase: true, matchBase: true }),
version,
});
}
else {
result.add({
name: dependency.startsWith(DefinitelyTyped)
? dependency.substring(DefinitelyTyped.length)
: dependency,
version,
});
}
}
/**
* Returns the project manifests that are used to resolve the dependencies imported by
* the module named `filename`, up to the passed working directory.
*/
const getManifests = (dir, workingDirectory, fileSystem) => {
const files = findPackageJsons(dir, workingDirectory, fileSystem);
return files.map(file => {
const content = file.content;
try {
return JSON.parse((0, files_js_1.stripBOM)(content.toString()));
}
catch (error) {
console.debug(`Error parsing file ${file.path}: ${error}`);
return {};
}
});
};
exports.getManifests = getManifests;
;