UNPKG

eslint-plugin-sonarjs

Version:
168 lines (167 loc) 6.76 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.packageJsonManifestResolver = void 0; const files_js_1 = require("../../files.js"); const index_js_1 = require("../index.js"); const closest_js_1 = require("../../find-up/closest.js"); const helpers_js_1 = require("./helpers.js"); const parse_js_1 = require("../parse.js"); const parsed_dependency_files_js_1 = require("../parsed-dependency-files.js"); exports.packageJsonManifestResolver = { resolve(dir, topDir, fileSystem) { const packageJson = (0, helpers_js_1.getManifestFileInDir)(index_js_1.PACKAGE_JSON, dir, topDir, fileSystem); if (!packageJson) { return []; } let parsedPackageJson = (0, parsed_dependency_files_js_1.parsePackageJson)(packageJson) ?? {}; let catalogSource = undefined; const closestParent = findClosestParentPackageJsonWithCatalogs(dir, topDir, fileSystem); if (closestParent) { // If the closest parent package.json has catalogs defined, we use it as the catalog source for resolving catalog references. const workspaces = Array.isArray(closestParent.workspaces) ? undefined : closestParent.workspaces; catalogSource = { catalog: workspaces?.catalog ?? closestParent.catalog, catalogs: workspaces?.catalogs ?? closestParent.catalogs, }; } else { // No parent package.json with catalogs found, we check if there's a pnpm workspace file that we can use as a catalog source. const pnpmWorkspaceFile = closest_js_1.closestPatternCache .get(index_js_1.PNPM_WORKSPACE_YAML, fileSystem) .get(topDir) .get(dir); const parsedPnpmWorkspace = pnpmWorkspaceFile ? (0, parsed_dependency_files_js_1.parsePnpmWorkspace)(pnpmWorkspaceFile) : undefined; if (parsedPnpmWorkspace) { parsedPackageJson = injectWorkspacePackages(parsedPackageJson, parsedPnpmWorkspace); catalogSource = parsedPnpmWorkspace; } } parsedPackageJson = resolveCatalogReferences(parsedPackageJson, catalogSource); // Match Node's resolution: explicit "module" is ESM, anything else (including // missing "type") is CommonJS. const moduleType = parsedPackageJson.type === 'module' ? 'module' : 'commonjs'; return [ { type: 'package-json', manifest: parsedPackageJson, dependencies: buildDependencies(parsedPackageJson), moduleType, }, ]; }, }; function buildDependencies(packageJson) { const dependencies = new Map(); const fieldsToVisit = [ 'name', 'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies', '_moduleAliases', 'workspaces', ]; for (const field of fieldsToVisit) { if (!packageJson[field]) { continue; } if (field === 'name') { (0, parse_js_1.addDependencies)(dependencies, { [packageJson[field]]: '*' }); continue; } if (field === 'workspaces') { (0, parse_js_1.addDependenciesArray)(dependencies, Array.isArray(packageJson[field]) ? packageJson[field] : (packageJson[field]?.packages ?? [])); continue; } (0, parse_js_1.addDependencies)(dependencies, packageJson[field]); } return dependencies; } function resolveCatalogReferences(packageJson, catalogSource) { const depFields = [ 'dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies', ]; const modifiedPackageJson = { ...packageJson }; for (const field of depFields) { const deps = packageJson[field]; if (!deps) { continue; } const resolvedDeps = {}; for (const [depName, depVersion] of Object.entries(deps)) { if (typeof depVersion === 'string' && depVersion.startsWith('catalog:')) { const catalogName = depVersion.slice('catalog:'.length).trim() || 'default'; const resolvedDep = catalogName === 'default' ? catalogSource?.catalog?.[depName] : catalogSource?.catalogs?.[catalogName]?.[depName]; resolvedDeps[depName] = resolvedDep ?? depVersion; !resolvedDep && console.debug(`Dependency "${depName}" could not be resolved for catalog "${catalogName}"`); } else { resolvedDeps[depName] = depVersion ?? ''; } } modifiedPackageJson[field] = resolvedDeps; } return modifiedPackageJson; } function injectWorkspacePackages(packageJson, pnpmWorkspace) { if (!pnpmWorkspace.packages || packageJson.workspaces) { return packageJson; } return { ...packageJson, workspaces: pnpmWorkspace.packages, }; } /** * Find the closest parent package.json with catalogs defined. * @param dir Directory to start the search from * @param topDir Top directory to stop the search at * @param fileSystem Filesystem to use for the search * @returns The closest parent package.json with catalogs, or undefined if no package.json with catalogs is found */ function findClosestParentPackageJsonWithCatalogs(dir, topDir, fileSystem) { if (dir === topDir) { // No point in searching for parent package.json if we're already at the top directory. return undefined; } let currentDir = (0, helpers_js_1.getParentDirPath)(dir); const cache = closest_js_1.closestPatternCache.get(index_js_1.PACKAGE_JSON, fileSystem).get(topDir); while (currentDir !== null) { const file = cache.get(currentDir); if (!file) { return undefined; } const parsed = (0, parsed_dependency_files_js_1.parsePackageJson)(file); if (parsed && hasCatalogs(parsed)) { return parsed; } const fileDir = (0, files_js_1.dirnamePath)(file.filePath); if (fileDir === topDir) { return undefined; } currentDir = (0, helpers_js_1.getParentDirPath)(fileDir); } return undefined; } function hasCatalogs(packageJson) { if (packageJson.catalog || packageJson.catalogs) { return true; } const { workspaces } = packageJson; if (workspaces && !Array.isArray(workspaces)) { return !!(workspaces.catalog || workspaces.catalogs); } return false; }