UNPKG

nx

Version:

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

349 lines (347 loc) • 14.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SyncError = void 0; exports.getSyncGeneratorChanges = getSyncGeneratorChanges; exports.flushSyncGeneratorChanges = flushSyncGeneratorChanges; exports.collectAllRegisteredSyncGenerators = collectAllRegisteredSyncGenerators; exports.runSyncGenerator = runSyncGenerator; exports.collectEnabledTaskSyncGeneratorsFromProjectGraph = collectEnabledTaskSyncGeneratorsFromProjectGraph; exports.collectEnabledTaskSyncGeneratorsFromTaskGraph = collectEnabledTaskSyncGeneratorsFromTaskGraph; exports.collectRegisteredGlobalSyncGenerators = collectRegisteredGlobalSyncGenerators; exports.getSyncGeneratorSuccessResultsMessageLines = getSyncGeneratorSuccessResultsMessageLines; exports.getFailedSyncGeneratorsFixMessageLines = getFailedSyncGeneratorsFixMessageLines; exports.getFlushFailureMessageLines = getFlushFailureMessageLines; exports.processSyncGeneratorResultErrors = processSyncGeneratorResultErrors; const perf_hooks_1 = require("perf_hooks"); const generate_1 = require("../command-line/generate/generate"); const generator_utils_1 = require("../command-line/generate/generator-utils"); const nx_json_1 = require("../config/nx-json"); const client_1 = require("../daemon/client/client"); const is_on_daemon_1 = require("../daemon/is-on-daemon"); const tree_1 = require("../generators/tree"); const project_graph_1 = require("../project-graph/project-graph"); const workspace_context_1 = require("./workspace-context"); const workspace_root_1 = require("./workspace-root"); const chalk = require("chalk"); class SyncError extends Error { constructor(title, bodyLines) { super(title); this.title = title; this.bodyLines = bodyLines; this.name = this.constructor.name; } } exports.SyncError = SyncError; async function getSyncGeneratorChanges(generators) { perf_hooks_1.performance.mark('get-sync-generators-changes:start'); let results; if (!client_1.daemonClient.enabled()) { results = await runSyncGenerators(generators); } else { results = await client_1.daemonClient.getSyncGeneratorChanges(generators); } perf_hooks_1.performance.mark('get-sync-generators-changes:end'); perf_hooks_1.performance.measure('get-sync-generators-changes', 'get-sync-generators-changes:start', 'get-sync-generators-changes:end'); return results.filter((r) => ('error' in r ? true : r.changes.length > 0)); } async function flushSyncGeneratorChanges(results) { if ((0, is_on_daemon_1.isOnDaemon)() || !client_1.daemonClient.enabled()) { return await flushSyncGeneratorChangesToDisk(results); } return await client_1.daemonClient.flushSyncGeneratorChangesToDisk(results.map((r) => r.generatorName)); } async function collectAllRegisteredSyncGenerators(projectGraph, nxJson) { if (!client_1.daemonClient.enabled()) { return { globalGenerators: [...collectRegisteredGlobalSyncGenerators()], taskGenerators: [ ...collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph, nxJson), ], }; } return await client_1.daemonClient.getRegisteredSyncGenerators(); } async function runSyncGenerator(tree, generatorSpecifier, projects) { try { perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:start`); const { collection, generator } = (0, generate_1.parseGeneratorString)(generatorSpecifier); const { implementationFactory } = (0, generator_utils_1.getGeneratorInformation)(collection, generator, workspace_root_1.workspaceRoot, projects); const implementation = implementationFactory(); const result = await implementation(tree); let callback; let outOfSyncMessage; if (result && typeof result === 'object') { callback = result.callback; outOfSyncMessage = result.outOfSyncMessage; } perf_hooks_1.performance.mark(`run-sync-generator:${generatorSpecifier}:end`); perf_hooks_1.performance.measure(`run-sync-generator:${generatorSpecifier}`, `run-sync-generator:${generatorSpecifier}:start`, `run-sync-generator:${generatorSpecifier}:end`); return { changes: tree.listChanges(), generatorName: generatorSpecifier, callback, outOfSyncMessage, }; } catch (e) { return { generatorName: generatorSpecifier, error: toSerializableError(e), }; } } function collectEnabledTaskSyncGeneratorsFromProjectGraph(projectGraph, nxJson) { const taskSyncGenerators = new Set(); const disabledTaskSyncGenerators = new Set(nxJson.sync?.disabledTaskSyncGenerators ?? []); for (const { data: { targets }, } of Object.values(projectGraph.nodes)) { if (!targets) { continue; } for (const target of Object.values(targets)) { if (!target.syncGenerators?.length) { continue; } for (const generator of target.syncGenerators) { if (!disabledTaskSyncGenerators.has(generator) && !taskSyncGenerators.has(generator)) { taskSyncGenerators.add(generator); } } } } return taskSyncGenerators; } function collectEnabledTaskSyncGeneratorsFromTaskGraph(taskGraph, projectGraph, nxJson) { const taskSyncGenerators = new Set(); const disabledTaskSyncGenerators = new Set(nxJson.sync?.disabledTaskSyncGenerators ?? []); for (const { target } of Object.values(taskGraph.tasks)) { const { syncGenerators } = projectGraph.nodes[target.project].data.targets[target.target]; if (!syncGenerators?.length) { continue; } for (const generator of syncGenerators) { if (!disabledTaskSyncGenerators.has(generator) && !taskSyncGenerators.has(generator)) { taskSyncGenerators.add(generator); } } } return taskSyncGenerators; } function collectRegisteredGlobalSyncGenerators(nxJson = (0, nx_json_1.readNxJson)()) { const globalSyncGenerators = new Set(); if (!nxJson.sync?.globalGenerators?.length) { return globalSyncGenerators; } for (const generator of nxJson.sync.globalGenerators) { globalSyncGenerators.add(generator); } return globalSyncGenerators; } function getSyncGeneratorSuccessResultsMessageLines(results) { const messageLines = []; for (const result of results) { if ('error' in result) { continue; } messageLines.push(`[${chalk.bold(result.generatorName)}]: ${result.outOfSyncMessage ?? `Some files are out of sync.`}`); } return messageLines; } function getFailedSyncGeneratorsFixMessageLines(results, verbose, globalGeneratorSet = new Set()) { const messageLines = []; const globalGenerators = []; const taskGenerators = []; let isFirst = true; for (const result of results) { if ('error' in result) { if (!isFirst && verbose) { messageLines.push(''); } isFirst = false; messageLines.push(`[${chalk.bold(result.generatorName)}]: ${errorToString(result.error, verbose)}`); if (globalGeneratorSet.has(result.generatorName)) { globalGenerators.push(result.generatorName); } else { taskGenerators.push(result.generatorName); } } } messageLines.push(...getFailedSyncGeneratorsMessageLines(taskGenerators, globalGenerators, verbose)); return messageLines; } function getFlushFailureMessageLines(result, verbose, globalGeneratorSet = new Set()) { const messageLines = []; const globalGenerators = []; const taskGenerators = []; let isFirst = true; for (const failure of result.generatorFailures) { if (!isFirst && verbose) { messageLines.push(''); } isFirst = false; messageLines.push(`[${chalk.bold(failure.generator)}]: ${errorToString(failure.error, verbose)}`); if (globalGeneratorSet.has(failure.generator)) { globalGenerators.push(failure.generator); } else { taskGenerators.push(failure.generator); } } messageLines.push(...getFailedSyncGeneratorsMessageLines(taskGenerators, globalGenerators, verbose)); if (result.generalFailure) { if (messageLines.length > 0) { messageLines.push(''); messageLines.push('Additionally, an unexpected error occurred:'); } else { messageLines.push('An unexpected error occurred:'); } messageLines.push(...[ '', result.generalFailure.message, ...(!!result.generalFailure.stack ? [`\n${result.generalFailure.stack}`] : []), '', 'Please report the error at: https://github.com/nrwl/nx/issues/new/choose', ]); } return messageLines; } function processSyncGeneratorResultErrors(results) { let failedGeneratorsCount = 0; for (const result of results) { if ('error' in result) { failedGeneratorsCount++; } } const areAllResultsFailures = failedGeneratorsCount === results.length; const anySyncGeneratorsFailed = failedGeneratorsCount > 0; return { failedGeneratorsCount, areAllResultsFailures, anySyncGeneratorsFailed, }; } async function runSyncGenerators(generators) { const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, 'running sync generators'); const projectGraph = await (0, project_graph_1.createProjectGraphAsync)(); const { projects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph); const results = []; for (const generator of generators) { const result = await runSyncGenerator(tree, generator, projects); results.push(result); } return results; } async function flushSyncGeneratorChangesToDisk(results) { perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:start'); const createdFiles = []; const updatedFiles = []; const deletedFiles = []; const generatorFailures = []; for (const result of results) { if ('error' in result) { continue; } for (const change of result.changes) { if (change.type === 'CREATE') { createdFiles.push(change.path); } else if (change.type === 'UPDATE') { updatedFiles.push(change.path); } else if (change.type === 'DELETE') { deletedFiles.push(change.path); } } try { // Write changes to disk (0, tree_1.flushChanges)(workspace_root_1.workspaceRoot, result.changes); // Run the callback if (result.callback) { await result.callback(); } } catch (e) { generatorFailures.push({ generator: result.generatorName, error: toSerializableError(e), }); } } try { // Update the context files await (0, workspace_context_1.updateContextWithChangedFiles)(workspace_root_1.workspaceRoot, createdFiles, updatedFiles, deletedFiles); perf_hooks_1.performance.mark('flush-sync-generator-changes-to-disk:end'); perf_hooks_1.performance.measure('flush sync generator changes to disk', 'flush-sync-generator-changes-to-disk:start', 'flush-sync-generator-changes-to-disk:end'); } catch (e) { return { generatorFailures, generalFailure: toSerializableError(e), }; } return generatorFailures.length > 0 ? { generatorFailures } : { success: true }; } function getFailedSyncGeneratorsMessageLines(taskGenerators, globalGenerators, verbose) { const messageLines = []; if (taskGenerators.length + globalGenerators.length === 1) { messageLines.push('', verbose ? 'Please check the error above and address the issue.' : 'Please check the error above and address the issue. You can provide the `--verbose` flag to get more details.'); if (taskGenerators.length === 1) { messageLines.push(`If needed, you can disable the failing sync generator by setting \`sync.disabledTaskSyncGenerators: ["${taskGenerators[0]}"]\` in your \`nx.json\`.`); } else { messageLines.push(`If needed, you can remove the failing global sync generator "${globalGenerators[0]}" from the \`sync.globalGenerators\` array in your \`nx.json\`.`); } } else if (taskGenerators.length + globalGenerators.length > 1) { messageLines.push('', verbose ? 'Please check the errors above and address the issues.' : 'Please check the errors above and address the issues. You can provide the `--verbose` flag to get more details.'); if (taskGenerators.length > 0) { const generatorsString = taskGenerators.map((g) => `"${g}"`).join(', '); messageLines.push(`If needed, you can disable the failing task sync generators by setting \`sync.disabledTaskSyncGenerators: [${generatorsString}]\` in your \`nx.json\`.`); } if (globalGenerators.length > 0) { const lastGenerator = globalGenerators.pop(); const generatorsString = globalGenerators.length > 0 ? `${globalGenerators .map((g) => `"${g}"`) .join(', ')} and "${lastGenerator}"` : `"${lastGenerator}"`; messageLines.push(`If needed, you can remove the failing global sync generators ${generatorsString} from the \`sync.globalGenerators\` array in your \`nx.json\`.`); } } return messageLines; } function errorToString(error, verbose) { if (error.title) { let message = `${chalk.red(error.title)}`; if (error.bodyLines?.length) { message += ` ${error.bodyLines .map((bodyLine) => `${bodyLine.split('\n').join('\n ')}`) .join('\n ')}`; return message; } } return `${chalk.red(error.message)}${verbose && error.stack ? '\n ' + error.stack : ''}`; } function toSerializableError(error) { return error instanceof SyncError ? { title: error.title, bodyLines: error.bodyLines, message: error.message, stack: error.stack, } : { message: error.message, stack: error.stack }; }