UNPKG

nx

Version:

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

316 lines (315 loc) • 13.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFileMap = getFileMap; exports.hydrateFileMap = hydrateFileMap; exports.buildProjectGraphUsingProjectFileMap = buildProjectGraphUsingProjectFileMap; exports.applyProjectMetadata = applyProjectMetadata; const workspace_root_1 = require("../utils/workspace-root"); const path_1 = require("path"); const perf_hooks_1 = require("perf_hooks"); const assert_workspace_validity_1 = require("../utils/assert-workspace-validity"); const nx_deps_cache_1 = require("./nx-deps-cache"); const implicit_project_dependencies_1 = require("./utils/implicit-project-dependencies"); const normalize_project_nodes_1 = require("./utils/normalize-project-nodes"); const typescript_1 = require("../plugins/js/utils/typescript"); const fileutils_1 = require("../utils/fileutils"); const project_graph_builder_1 = require("./project-graph-builder"); const configuration_1 = require("../config/configuration"); const fs_1 = require("fs"); const error_types_1 = require("./error-types"); const project_configuration_utils_1 = require("./utils/project-configuration-utils"); const delayed_spinner_1 = require("../utils/delayed-spinner"); let storedFileMap = null; let storedAllWorkspaceFiles = null; let storedRustReferences = null; function getFileMap() { if (!!storedFileMap) { return { fileMap: storedFileMap, allWorkspaceFiles: storedAllWorkspaceFiles, rustReferences: storedRustReferences, }; } else { return { fileMap: { nonProjectFiles: [], projectFileMap: {}, }, allWorkspaceFiles: [], rustReferences: null, }; } } function hydrateFileMap(fileMap, allWorkspaceFiles, rustReferences) { storedFileMap = fileMap; storedAllWorkspaceFiles = allWorkspaceFiles; storedRustReferences = rustReferences; } async function buildProjectGraphUsingProjectFileMap(projectRootMap, externalNodes, fileMap, allWorkspaceFiles, rustReferences, fileMapCache, plugins, sourceMap) { storedFileMap = fileMap; storedAllWorkspaceFiles = allWorkspaceFiles; storedRustReferences = rustReferences; const projects = {}; for (const root in projectRootMap) { const project = projectRootMap[root]; projects[project.name] = project; } const errors = []; const nxJson = (0, configuration_1.readNxJson)(); const projectGraphVersion = '6.0'; try { (0, assert_workspace_validity_1.assertWorkspaceValidity)(projects, nxJson); } catch (e) { if ((0, error_types_1.isWorkspaceValidityError)(e)) { errors.push(e); } } const packageJsonDeps = readCombinedDeps(); const rootTsConfig = readRootTsConfig(); let filesToProcess; let cachedFileData; const useCacheData = fileMapCache && !(0, nx_deps_cache_1.shouldRecomputeWholeGraph)(fileMapCache, packageJsonDeps, projects, nxJson, rootTsConfig); if (useCacheData) { const fromCache = (0, nx_deps_cache_1.extractCachedFileData)(fileMap, fileMapCache); filesToProcess = fromCache.filesToProcess; cachedFileData = fromCache.cachedFileData; } else { filesToProcess = fileMap; cachedFileData = { nonProjectFiles: {}, projectFileMap: {}, }; } let projectGraph; let projectFileMapCache; try { const context = createContext(projects, nxJson, externalNodes, fileMap, filesToProcess); projectGraph = await buildProjectGraphUsingContext(externalNodes, context, cachedFileData, projectGraphVersion, plugins, sourceMap); projectFileMapCache = (0, nx_deps_cache_1.createProjectFileMapCache)(nxJson, packageJsonDeps, fileMap, rootTsConfig); } catch (e) { // we need to include the workspace validity errors in the final error if ((0, error_types_1.isAggregateProjectGraphError)(e)) { errors.push(...e.errors); throw new error_types_1.AggregateProjectGraphError(errors, e.partialProjectGraph); } else { throw e; } } if (errors.length > 0) { throw new error_types_1.AggregateProjectGraphError(errors, projectGraph); } return { projectGraph, projectFileMapCache, }; } function readCombinedDeps() { const installationPackageJsonPath = (0, path_1.join)(workspace_root_1.workspaceRoot, '.nx', 'installation', 'package.json'); const installationPackageJson = (0, fs_1.existsSync)(installationPackageJsonPath) ? (0, fileutils_1.readJsonFile)(installationPackageJsonPath) : {}; const rootPackageJsonPath = (0, path_1.join)(workspace_root_1.workspaceRoot, 'package.json'); const rootPackageJson = (0, fs_1.existsSync)(rootPackageJsonPath) ? (0, fileutils_1.readJsonFile)(rootPackageJsonPath) : {}; return { ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies, ...installationPackageJson.dependencies, ...installationPackageJson.devDependencies, }; } async function buildProjectGraphUsingContext(knownExternalNodes, ctx, cachedFileData, projectGraphVersion, plugins, sourceMap) { const builder = new project_graph_builder_1.ProjectGraphBuilder(null, ctx.fileMap.projectFileMap); builder.setVersion(projectGraphVersion); for (const node in knownExternalNodes) { builder.addExternalNode(knownExternalNodes[node]); } await (0, normalize_project_nodes_1.normalizeProjectNodes)(ctx, builder); const initProjectGraph = builder.getUpdatedProjectGraph(); let updatedGraph; let error; try { updatedGraph = await updateProjectGraphWithPlugins(ctx, initProjectGraph, plugins, sourceMap); } catch (e) { if ((0, error_types_1.isAggregateProjectGraphError)(e)) { updatedGraph = e.partialProjectGraph; error = e; } else { throw e; } } const updatedBuilder = new project_graph_builder_1.ProjectGraphBuilder(updatedGraph, ctx.fileMap.projectFileMap); for (const proj of Object.keys(cachedFileData.projectFileMap)) { for (const f of ctx.fileMap.projectFileMap[proj] || []) { const cached = cachedFileData.projectFileMap[proj][f.file]; if (cached && cached.deps) { f.deps = [...cached.deps]; } } } for (const file of ctx.fileMap.nonProjectFiles) { const cached = cachedFileData.nonProjectFiles[file.file]; if (cached?.deps) { file.deps = [...cached.deps]; } } (0, implicit_project_dependencies_1.applyImplicitDependencies)(ctx.projects, updatedBuilder); const finalGraph = updatedBuilder.getUpdatedProjectGraph(); if (!error) { return finalGraph; } else { throw new error_types_1.AggregateProjectGraphError(error.errors, finalGraph); } } function createContext(projects, nxJson, externalNodes, fileMap, filesToProcess) { return { nxJsonConfiguration: nxJson, projects, externalNodes, workspaceRoot: workspace_root_1.workspaceRoot, fileMap, filesToProcess, }; } async function updateProjectGraphWithPlugins(context, initProjectGraph, plugins, sourceMap) { let graph = initProjectGraph; const errors = []; const builder = new project_graph_builder_1.ProjectGraphBuilder(graph, context.fileMap.projectFileMap, context.fileMap.nonProjectFiles); const createDependencyPlugins = plugins.filter((plugin) => plugin.createDependencies); perf_hooks_1.performance.mark('createDependencies:start'); let spinner; const inProgressPlugins = new Set(); function updateSpinner() { if (!spinner || inProgressPlugins.size === 0) { return; } if (inProgressPlugins.size === 1) { spinner.setMessage(`Creating project graph dependencies with ${inProgressPlugins.values().next().value}`); } else if (process.env.NX_VERBOSE_LOGGING === 'true') { spinner.setMessage([ `Creating project graph dependencies with ${inProgressPlugins.size} plugins`, ...Array.from(inProgressPlugins).map((p) => ` - ${p}`), ].join('\n')); } else { spinner.setMessage(`Creating project graph dependencies with ${inProgressPlugins.size} plugins`); } } spinner = new delayed_spinner_1.DelayedSpinner(`Creating project graph dependencies with ${plugins.length} plugins`); await Promise.all(createDependencyPlugins.map(async (plugin) => { perf_hooks_1.performance.mark(`${plugin.name}:createDependencies - start`); inProgressPlugins.add(plugin.name); try { const dependencies = await plugin .createDependencies({ ...context, }) .finally(() => { inProgressPlugins.delete(plugin.name); updateSpinner(); }); for (const dep of dependencies) { builder.addDependency(dep.source, dep.target, dep.type, 'sourceFile' in dep ? dep.sourceFile : null); } } catch (cause) { errors.push(new error_types_1.ProcessDependenciesError(plugin.name, { cause, })); } perf_hooks_1.performance.mark(`${plugin.name}:createDependencies - end`); perf_hooks_1.performance.measure(`${plugin.name}:createDependencies`, `${plugin.name}:createDependencies - start`, `${plugin.name}:createDependencies - end`); })); perf_hooks_1.performance.mark('createDependencies:end'); perf_hooks_1.performance.measure(`createDependencies`, `createDependencies:start`, `createDependencies:end`); spinner?.cleanup(); const graphWithDeps = builder.getUpdatedProjectGraph(); const { errors: metadataErrors, graph: updatedGraph } = await applyProjectMetadata(graphWithDeps, plugins, { nxJsonConfiguration: context.nxJsonConfiguration, workspaceRoot: workspace_root_1.workspaceRoot, }, sourceMap); errors.push(...metadataErrors); if (errors.length > 0) { throw new error_types_1.AggregateProjectGraphError(errors, updatedGraph); } return updatedGraph; } function readRootTsConfig() { try { const tsConfigPath = (0, typescript_1.getRootTsConfigPath)(); if (tsConfigPath) { return (0, fileutils_1.readJsonFile)(tsConfigPath, { expectComments: true }); } } catch (e) { return {}; } } async function applyProjectMetadata(graph, plugins, context, sourceMap) { const results = []; const errors = []; perf_hooks_1.performance.mark('createMetadata:start'); let spinner; const inProgressPlugins = new Set(); function updateSpinner() { if (!spinner || inProgressPlugins.size === 0) { return; } if (inProgressPlugins.size === 1) { spinner.setMessage(`Creating project metadata with ${inProgressPlugins.values().next().value}`); } else if (process.env.NX_VERBOSE_LOGGING === 'true') { spinner.setMessage([ `Creating project metadata with ${inProgressPlugins.size} plugins`, ...Array.from(inProgressPlugins).map((p) => ` - ${p}`), ].join('\n')); } else { spinner.setMessage(`Creating project metadata with ${inProgressPlugins.size} plugins`); } } spinner = new delayed_spinner_1.DelayedSpinner(`Creating project metadata with ${plugins.length} plugins`); const promises = plugins.map(async (plugin) => { if (plugin.createMetadata) { perf_hooks_1.performance.mark(`${plugin.name}:createMetadata - start`); inProgressPlugins.add(plugin.name); try { const metadata = await plugin.createMetadata(graph, context); results.push({ metadata, pluginName: plugin.name }); } catch (e) { errors.push(new error_types_1.CreateMetadataError(e, plugin.name)); } finally { inProgressPlugins.delete(plugin.name); updateSpinner(); perf_hooks_1.performance.mark(`${plugin.name}:createMetadata - end`); perf_hooks_1.performance.measure(`${plugin.name}:createMetadata`, `${plugin.name}:createMetadata - start`, `${plugin.name}:createMetadata - end`); } } }); await Promise.all(promises); spinner?.cleanup(); for (const { metadata: projectsMetadata, pluginName } of results) { for (const project in projectsMetadata) { const projectConfiguration = graph.nodes[project]?.data; if (projectConfiguration) { projectConfiguration.metadata = (0, project_configuration_utils_1.mergeMetadata)(sourceMap[project], [null, pluginName], 'metadata', projectsMetadata[project].metadata, projectConfiguration.metadata); } } } perf_hooks_1.performance.mark('createMetadata:end'); perf_hooks_1.performance.measure(`createMetadata`, `createMetadata:start`, `createMetadata:end`); return { errors, graph }; }