UNPKG

nx

Version:

The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.

166 lines (165 loc) • 7.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createDependencies = exports.createNodesV2 = exports.name = void 0; const fs_1 = require("fs"); const path_1 = require("path"); const perf_hooks_1 = require("perf_hooks"); const file_hasher_1 = require("../../hasher/file-hasher"); const plugins_1 = require("../../project-graph/plugins"); const cache_directory_1 = require("../../utils/cache-directory"); const globs_1 = require("../../utils/globs"); const package_manager_1 = require("../../utils/package-manager"); const versions_1 = require("../../utils/versions"); const workspace_root_1 = require("../../utils/workspace-root"); const bun_parser_1 = require("./lock-file/bun-parser"); const lock_file_1 = require("./lock-file/lock-file"); const build_dependencies_1 = require("./project-graph/build-dependencies/build-dependencies"); const config_1 = require("./utils/config"); exports.name = 'nx/js/dependencies-and-lockfile'; // Separate in-memory caches let cachedExternalNodes; let cachedKeyMap; exports.createNodesV2 = [ (0, globs_1.combineGlobPatterns)(lock_file_1.LOCKFILES), (files, _, context) => { return (0, plugins_1.createNodesFromFiles)(internalCreateNodes, files, _, context); }, ]; function internalCreateNodes(lockFile, _, context) { const pluginConfig = (0, config_1.jsPluginConfig)(context.nxJsonConfiguration); if (!pluginConfig.analyzeLockfile) { return {}; } const packageManager = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot); // Only process the correct lockfile if (lockFile !== (0, lock_file_1.getLockFileName)(packageManager)) { return {}; } const lockFilePath = (0, path_1.join)(workspace_root_1.workspaceRoot, lockFile); const lockFileContents = packageManager !== 'bun' ? (0, fs_1.readFileSync)(lockFilePath, 'utf-8') : (0, bun_parser_1.readBunLockFile)(lockFilePath); const lockFileHash = getLockFileHash(lockFileContents); if (!lockFileNeedsReprocessing(lockFileHash, externalNodesHashFile)) { const { nodes, keyMap } = readCachedExternalNodes(); cachedExternalNodes = nodes; cachedKeyMap = keyMap; return { externalNodes: nodes, }; } const { nodes: externalNodes, keyMap } = (0, lock_file_1.getLockFileNodes)(packageManager, lockFileContents, lockFileHash, context); cachedExternalNodes = externalNodes; cachedKeyMap = keyMap; writeExternalNodesCache(lockFileHash, externalNodes, keyMap); return { externalNodes, }; } const createDependencies = (_, ctx) => { const pluginConfig = (0, config_1.jsPluginConfig)(ctx.nxJsonConfiguration); const packageManager = (0, package_manager_1.detectPackageManager)(workspace_root_1.workspaceRoot); let lockfileDependencies = []; // lockfile may not exist yet if (pluginConfig.analyzeLockfile && (0, lock_file_1.lockFileExists)(packageManager) && cachedExternalNodes) { const lockFilePath = (0, path_1.join)(workspace_root_1.workspaceRoot, (0, lock_file_1.getLockFileName)(packageManager)); const lockFileContents = packageManager !== 'bun' ? (0, fs_1.readFileSync)(lockFilePath, 'utf-8') : (0, bun_parser_1.readBunLockFile)(lockFilePath); const lockFileHash = getLockFileHash(lockFileContents); if (!lockFileNeedsReprocessing(lockFileHash, dependenciesHashFile)) { lockfileDependencies = readCachedDependencies(); } else { lockfileDependencies = (0, lock_file_1.getLockFileDependencies)(packageManager, lockFileContents, lockFileHash, ctx, cachedKeyMap); writeDependenciesCache(lockFileHash, lockfileDependencies); } } perf_hooks_1.performance.mark('build typescript dependencies - start'); const explicitProjectDependencies = (0, build_dependencies_1.buildExplicitDependencies)(pluginConfig, ctx); perf_hooks_1.performance.mark('build typescript dependencies - end'); perf_hooks_1.performance.measure('build typescript dependencies', 'build typescript dependencies - start', 'build typescript dependencies - end'); return lockfileDependencies.concat(explicitProjectDependencies); }; exports.createDependencies = createDependencies; function getLockFileHash(lockFileContents) { return (0, file_hasher_1.hashArray)([versions_1.nxVersion, lockFileContents]); } // Serialize keyMap to JSON-friendly format function serializeKeyMap(keyMap) { const serialized = {}; for (const [key, value] of keyMap.entries()) { if (value instanceof Set) { // pnpm: Map<string, Set<ProjectGraphExternalNode>> serialized[key] = Array.from(value).map((node) => node.name); } else if (value && typeof value === 'object' && 'name' in value) { // npm/yarn: Map<string, ProjectGraphExternalNode> serialized[key] = value.name; } else { serialized[key] = value; } } return serialized; } // Deserialize keyMap from JSON format using ctx.externalNodes function deserializeKeyMap(serialized, externalNodes) { const keyMap = new Map(); for (const [key, value] of Object.entries(serialized)) { if (Array.isArray(value)) { // pnpm: reconstruct Set<ProjectGraphExternalNode> const nodes = value .map((nodeName) => externalNodes[nodeName]) .filter(Boolean); keyMap.set(key, new Set(nodes)); } else if (typeof value === 'string') { // npm/yarn: reconstruct ProjectGraphExternalNode const node = externalNodes[value]; if (node) { keyMap.set(key, node); } } else { keyMap.set(key, value); } } return keyMap; } function lockFileNeedsReprocessing(lockHash, hashFilePath) { try { return (0, fs_1.readFileSync)(hashFilePath).toString() !== lockHash; } catch { return true; } } // External nodes cache functions function writeExternalNodesCache(hash, nodes, keyMap) { (0, fs_1.mkdirSync)((0, path_1.dirname)(externalNodesHashFile), { recursive: true }); const serializedKeyMap = serializeKeyMap(keyMap); const cacheData = { nodes, keyMap: serializedKeyMap }; (0, fs_1.writeFileSync)(externalNodesCache, JSON.stringify(cacheData, null, 2)); (0, fs_1.writeFileSync)(externalNodesHashFile, hash); } function readCachedExternalNodes() { const { nodes, keyMap } = JSON.parse((0, fs_1.readFileSync)(externalNodesCache, 'utf-8')); return { nodes, keyMap: deserializeKeyMap(keyMap, nodes) }; } // Dependencies cache functions function writeDependenciesCache(hash, dependencies) { (0, fs_1.mkdirSync)((0, path_1.dirname)(dependenciesHashFile), { recursive: true }); (0, fs_1.writeFileSync)(dependenciesCache, JSON.stringify(dependencies, null, 2)); (0, fs_1.writeFileSync)(dependenciesHashFile, hash); } function readCachedDependencies() { return JSON.parse((0, fs_1.readFileSync)(dependenciesCache).toString()); } // Cache file paths const externalNodesHashFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'lockfile-nodes.hash'); const dependenciesHashFile = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'lockfile-dependencies.hash'); const externalNodesCache = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'parsed-lock-file.nodes.json'); const dependenciesCache = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, 'parsed-lock-file.dependencies.json');