nx 19.6.0-beta.1 → 19.6.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/bin/post-install.js +8 -0
  2. package/package.json +12 -12
  3. package/schemas/nx-schema.json +55 -4
  4. package/schemas/project-schema.json +7 -0
  5. package/src/adapter/compat.d.ts +1 -1
  6. package/src/adapter/compat.js +1 -0
  7. package/src/command-line/nx-commands.js +3 -0
  8. package/src/command-line/release/changelog.js +9 -9
  9. package/src/command-line/release/command-object.d.ts +12 -3
  10. package/src/command-line/release/command-object.js +16 -1
  11. package/src/command-line/release/config/config.js +4 -2
  12. package/src/command-line/release/config/filter-release-groups.d.ts +2 -2
  13. package/src/command-line/release/config/filter-release-groups.js +1 -1
  14. package/src/command-line/release/config/version-plans.d.ts +1 -1
  15. package/src/command-line/release/config/version-plans.js +12 -12
  16. package/src/command-line/release/plan-check.d.ts +4 -0
  17. package/src/command-line/release/plan-check.js +225 -0
  18. package/src/command-line/release/plan.js +1 -1
  19. package/src/command-line/release/release.js +3 -3
  20. package/src/command-line/release/version.js +1 -1
  21. package/src/command-line/sync/command-object.d.ts +6 -0
  22. package/src/command-line/sync/command-object.js +25 -0
  23. package/src/command-line/sync/sync.d.ts +6 -0
  24. package/src/command-line/sync/sync.js +30 -0
  25. package/src/config/nx-json.d.ts +32 -2
  26. package/src/config/workspace-json-project-json.d.ts +5 -0
  27. package/src/daemon/client/client.d.ts +5 -0
  28. package/src/daemon/client/client.js +33 -0
  29. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.d.ts +6 -0
  30. package/src/daemon/message-types/flush-sync-generator-changes-to-disk.js +11 -0
  31. package/src/daemon/message-types/get-registered-sync-generators.d.ts +5 -0
  32. package/src/daemon/message-types/get-registered-sync-generators.js +11 -0
  33. package/src/daemon/message-types/get-sync-generator-changes.d.ts +6 -0
  34. package/src/daemon/message-types/get-sync-generator-changes.js +11 -0
  35. package/src/daemon/message-types/update-workspace-context.d.ts +8 -0
  36. package/src/daemon/message-types/update-workspace-context.js +11 -0
  37. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.d.ts +2 -0
  38. package/src/daemon/server/handle-flush-sync-generator-changes-to-disk.js +11 -0
  39. package/src/daemon/server/handle-get-registered-sync-generators.d.ts +2 -0
  40. package/src/daemon/server/handle-get-registered-sync-generators.js +11 -0
  41. package/src/daemon/server/handle-get-sync-generator-changes.d.ts +2 -0
  42. package/src/daemon/server/handle-get-sync-generator-changes.js +17 -0
  43. package/src/daemon/server/handle-update-workspace-context.d.ts +2 -0
  44. package/src/daemon/server/handle-update-workspace-context.js +11 -0
  45. package/src/daemon/server/project-graph-incremental-recomputation.d.ts +1 -0
  46. package/src/daemon/server/project-graph-incremental-recomputation.js +19 -2
  47. package/src/daemon/server/server.js +25 -0
  48. package/src/daemon/server/sync-generators.d.ts +6 -0
  49. package/src/daemon/server/sync-generators.js +202 -0
  50. package/src/daemon/socket-utils.js +18 -5
  51. package/src/daemon/tmp-dir.js +2 -1
  52. package/src/native/nx.wasm32-wasi.wasm +0 -0
  53. package/src/nx-cloud/generators/connect-to-nx-cloud/connect-to-nx-cloud.js +1 -1
  54. package/src/tasks-runner/run-command.d.ts +1 -1
  55. package/src/tasks-runner/run-command.js +120 -2
  56. package/src/utils/command-line-utils.js +1 -1
  57. package/src/utils/plugins/output.js +1 -1
  58. package/src/utils/sync-generators.d.ts +22 -0
  59. package/src/utils/sync-generators.js +161 -0
  60. package/src/utils/workspace-context.d.ts +1 -0
  61. package/src/utils/workspace-context.js +16 -0
  62. package/src/daemon/message-types/update-context-files.d.ts +0 -7
  63. package/src/daemon/message-types/update-context-files.js +0 -11
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.currentProjectGraph = exports.currentProjectFileMapCache = exports.fileMapWithFiles = void 0;
4
4
  exports.getCachedSerializedProjectGraphPromise = getCachedSerializedProjectGraphPromise;
5
5
  exports.addUpdatedAndDeletedFiles = addUpdatedAndDeletedFiles;
6
+ exports.registerProjectGraphRecomputationListener = registerProjectGraphRecomputationListener;
6
7
  const perf_hooks_1 = require("perf_hooks");
7
8
  const nx_json_1 = require("../../config/nx-json");
8
9
  const file_hasher_1 = require("../../hasher/file-hasher");
@@ -20,14 +21,17 @@ const error_types_1 = require("../../project-graph/error-types");
20
21
  let cachedSerializedProjectGraphPromise;
21
22
  const collectedUpdatedFiles = new Set();
22
23
  const collectedDeletedFiles = new Set();
24
+ const projectGraphRecomputationListeners = new Set();
23
25
  let storedWorkspaceConfigHash;
24
26
  let waitPeriod = 100;
25
27
  let scheduledTimeoutId;
26
28
  let knownExternalNodes = {};
27
29
  async function getCachedSerializedProjectGraphPromise() {
28
30
  try {
31
+ let wasScheduled = false;
29
32
  // recomputing it now on demand. we can ignore the scheduled timeout
30
33
  if (scheduledTimeoutId) {
34
+ wasScheduled = true;
31
35
  clearTimeout(scheduledTimeoutId);
32
36
  scheduledTimeoutId = undefined;
33
37
  }
@@ -45,7 +49,11 @@ async function getCachedSerializedProjectGraphPromise() {
45
49
  cachedSerializedProjectGraphPromise =
46
50
  processFilesAndCreateAndSerializeProjectGraph(plugins);
47
51
  }
48
- return await cachedSerializedProjectGraphPromise;
52
+ const result = await cachedSerializedProjectGraphPromise;
53
+ if (wasScheduled) {
54
+ notifyProjectGraphRecomputationListeners(result.projectGraph);
55
+ }
56
+ return result;
49
57
  }
50
58
  catch (e) {
51
59
  return {
@@ -83,13 +91,17 @@ function addUpdatedAndDeletedFiles(createdFiles, updatedFiles, deletedFiles) {
83
91
  }
84
92
  cachedSerializedProjectGraphPromise =
85
93
  processFilesAndCreateAndSerializeProjectGraph(await (0, plugins_1.getPlugins)());
86
- await cachedSerializedProjectGraphPromise;
94
+ const { projectGraph } = await cachedSerializedProjectGraphPromise;
87
95
  if (createdFiles.length > 0) {
88
96
  (0, file_watcher_sockets_1.notifyFileWatcherSockets)(createdFiles, null, null);
89
97
  }
98
+ notifyProjectGraphRecomputationListeners(projectGraph);
90
99
  }, waitPeriod);
91
100
  }
92
101
  }
102
+ function registerProjectGraphRecomputationListener(listener) {
103
+ projectGraphRecomputationListeners.add(listener);
104
+ }
93
105
  function computeWorkspaceConfigHash(projectsConfigurations) {
94
106
  const projectConfigurationStrings = Object.entries(projectsConfigurations)
95
107
  .sort(([projectNameA], [projectNameB]) => projectNameA.localeCompare(projectNameB))
@@ -281,3 +293,8 @@ async function resetInternalStateIfNxDepsMissing() {
281
293
  await resetInternalState();
282
294
  }
283
295
  }
296
+ function notifyProjectGraphRecomputationListeners(projectGraph) {
297
+ for (const listener of projectGraphRecomputationListeners) {
298
+ listener(projectGraph);
299
+ }
300
+ }
@@ -42,6 +42,15 @@ const handle_get_task_history_1 = require("./handle-get-task-history");
42
42
  const handle_write_task_runs_to_history_1 = require("./handle-write-task-runs-to-history");
43
43
  const force_shutdown_1 = require("../message-types/force-shutdown");
44
44
  const handle_force_shutdown_1 = require("./handle-force-shutdown");
45
+ const get_sync_generator_changes_1 = require("../message-types/get-sync-generator-changes");
46
+ const handle_get_sync_generator_changes_1 = require("./handle-get-sync-generator-changes");
47
+ const sync_generators_1 = require("./sync-generators");
48
+ const get_registered_sync_generators_1 = require("../message-types/get-registered-sync-generators");
49
+ const handle_get_registered_sync_generators_1 = require("./handle-get-registered-sync-generators");
50
+ const update_workspace_context_1 = require("../message-types/update-workspace-context");
51
+ const handle_update_workspace_context_1 = require("./handle-update-workspace-context");
52
+ const flush_sync_generator_changes_to_disk_1 = require("../message-types/flush-sync-generator-changes-to-disk");
53
+ const handle_flush_sync_generator_changes_to_disk_1 = require("./handle-flush-sync-generator-changes-to-disk");
45
54
  let performanceObserver;
46
55
  let workspaceWatcherError;
47
56
  let outputsWatcherError;
@@ -140,6 +149,18 @@ async function handleMessage(socket, data) {
140
149
  else if ((0, force_shutdown_1.isHandleForceShutdownMessage)(payload)) {
141
150
  await handleResult(socket, 'FORCE_SHUTDOWN', () => (0, handle_force_shutdown_1.handleForceShutdown)(server));
142
151
  }
152
+ else if ((0, get_sync_generator_changes_1.isHandleGetSyncGeneratorChangesMessage)(payload)) {
153
+ await handleResult(socket, get_sync_generator_changes_1.GET_SYNC_GENERATOR_CHANGES, () => (0, handle_get_sync_generator_changes_1.handleGetSyncGeneratorChanges)(payload.generators));
154
+ }
155
+ else if ((0, flush_sync_generator_changes_to_disk_1.isHandleFlushSyncGeneratorChangesToDiskMessage)(payload)) {
156
+ await handleResult(socket, flush_sync_generator_changes_to_disk_1.FLUSH_SYNC_GENERATOR_CHANGES_TO_DISK, () => (0, handle_flush_sync_generator_changes_to_disk_1.handleFlushSyncGeneratorChangesToDisk)(payload.generators));
157
+ }
158
+ else if ((0, get_registered_sync_generators_1.isHandleGetRegisteredSyncGeneratorsMessage)(payload)) {
159
+ await handleResult(socket, get_registered_sync_generators_1.GET_REGISTERED_SYNC_GENERATORS, () => (0, handle_get_registered_sync_generators_1.handleGetRegisteredSyncGenerators)());
160
+ }
161
+ else if ((0, update_workspace_context_1.isHandleUpdateWorkspaceContextMessage)(payload)) {
162
+ await handleResult(socket, update_workspace_context_1.UPDATE_WORKSPACE_CONTEXT, () => (0, handle_update_workspace_context_1.handleUpdateWorkspaceContext)(payload.createdFiles, payload.updatedFiles, payload.deletedFiles));
163
+ }
143
164
  else {
144
165
  await (0, shutdown_utils_1.respondWithErrorAndExit)(socket, `Invalid payload from the client`, new Error(`Unsupported payload sent to daemon server: ${unparsedPayload}`));
145
166
  }
@@ -339,6 +360,10 @@ async function startServer() {
339
360
  if (!(0, shutdown_utils_1.getOutputWatcherInstance)()) {
340
361
  (0, shutdown_utils_1.storeOutputWatcherInstance)(await (0, watcher_1.watchOutputFiles)(handleOutputsChanges));
341
362
  }
363
+ // listen for project graph recomputation events to collect and schedule sync generators
364
+ (0, project_graph_incremental_recomputation_1.registerProjectGraphRecomputationListener)(sync_generators_1.collectAndScheduleSyncGenerators);
365
+ // trigger an initial project graph recomputation
366
+ (0, project_graph_incremental_recomputation_1.addUpdatedAndDeletedFiles)([], [], []);
342
367
  return resolve(server);
343
368
  }
344
369
  catch (err) {
@@ -0,0 +1,6 @@
1
+ import type { ProjectGraph } from '../../config/project-graph';
2
+ import { type SyncGeneratorChangesResult } from '../../utils/sync-generators';
3
+ export declare function getCachedSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorChangesResult[]>;
4
+ export declare function flushSyncGeneratorChangesToDisk(generators: string[]): Promise<void>;
5
+ export declare function collectAndScheduleSyncGenerators(projectGraph: ProjectGraph): void;
6
+ export declare function getCachedRegisteredSyncGenerators(): Promise<string[]>;
@@ -0,0 +1,202 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCachedSyncGeneratorChanges = getCachedSyncGeneratorChanges;
4
+ exports.flushSyncGeneratorChangesToDisk = flushSyncGeneratorChangesToDisk;
5
+ exports.collectAndScheduleSyncGenerators = collectAndScheduleSyncGenerators;
6
+ exports.getCachedRegisteredSyncGenerators = getCachedRegisteredSyncGenerators;
7
+ const nx_json_1 = require("../../config/nx-json");
8
+ const tree_1 = require("../../generators/tree");
9
+ const file_hasher_1 = require("../../hasher/file-hasher");
10
+ const project_graph_1 = require("../../project-graph/project-graph");
11
+ const sync_generators_1 = require("../../utils/sync-generators");
12
+ const workspace_root_1 = require("../../utils/workspace-root");
13
+ const logger_1 = require("./logger");
14
+ const project_graph_incremental_recomputation_1 = require("./project-graph-incremental-recomputation");
15
+ const syncGeneratorsCacheResultPromises = new Map();
16
+ let registeredTaskSyncGenerators = new Set();
17
+ let registeredGlobalSyncGenerators = new Set();
18
+ const scheduledGenerators = new Set();
19
+ let waitPeriod = 100;
20
+ let registeredSyncGenerators;
21
+ let scheduledTimeoutId;
22
+ let storedProjectGraphHash;
23
+ let storedNxJsonHash;
24
+ const log = (...messageParts) => {
25
+ logger_1.serverLogger.log('[SYNC]:', ...messageParts);
26
+ };
27
+ // TODO(leo): check conflicts and reuse the Tree where possible
28
+ async function getCachedSyncGeneratorChanges(generators) {
29
+ try {
30
+ log('get sync generators changes on demand', generators);
31
+ // this is invoked imperatively, so we clear any scheduled run
32
+ if (scheduledTimeoutId) {
33
+ log('clearing scheduled run');
34
+ clearTimeout(scheduledTimeoutId);
35
+ scheduledTimeoutId = undefined;
36
+ }
37
+ // reset the wait time
38
+ waitPeriod = 100;
39
+ let projects;
40
+ let errored = false;
41
+ const getProjectsConfigurations = async () => {
42
+ if (projects || errored) {
43
+ return projects;
44
+ }
45
+ const { projectGraph, error } = await (0, project_graph_incremental_recomputation_1.getCachedSerializedProjectGraphPromise)();
46
+ projects = projectGraph
47
+ ? (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph).projects
48
+ : null;
49
+ errored = error !== undefined;
50
+ return projects;
51
+ };
52
+ return (await Promise.all(generators.map(async (generator) => {
53
+ if (scheduledGenerators.has(generator) ||
54
+ !syncGeneratorsCacheResultPromises.has(generator)) {
55
+ // it's scheduled to run (there are pending changes to process) or
56
+ // it's not scheduled and there's no cached result, so run it
57
+ const projects = await getProjectsConfigurations();
58
+ if (projects) {
59
+ log(generator, 'already scheduled or not cached, running it now');
60
+ runGenerator(generator, projects);
61
+ }
62
+ else {
63
+ log(generator, 'already scheduled or not cached, project graph errored');
64
+ /**
65
+ * This should never happen. This is invoked imperatively, and by
66
+ * the time it is invoked, the project graph would have already
67
+ * been requested. If it errored, it would have been reported and
68
+ * this wouldn't have been invoked. We handle it just in case.
69
+ *
70
+ * Since the project graph would be reported by the relevant
71
+ * handlers separately, we just ignore the error, don't cache
72
+ * any result and return an empty result, the next time this is
73
+ * invoked the process will repeat until it eventually recovers
74
+ * when the project graph is fixed.
75
+ */
76
+ return Promise.resolve({ changes: [], generatorName: generator });
77
+ }
78
+ }
79
+ else {
80
+ log(generator, 'not scheduled and has cached result, returning cached result');
81
+ }
82
+ return syncGeneratorsCacheResultPromises.get(generator);
83
+ }))).flat();
84
+ }
85
+ catch (e) {
86
+ console.error(e);
87
+ syncGeneratorsCacheResultPromises.clear();
88
+ return [];
89
+ }
90
+ }
91
+ async function flushSyncGeneratorChangesToDisk(generators) {
92
+ log('flush sync generators changes', generators);
93
+ const results = await getCachedSyncGeneratorChanges(generators);
94
+ for (const generator of generators) {
95
+ syncGeneratorsCacheResultPromises.delete(generator);
96
+ }
97
+ await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
98
+ }
99
+ function collectAndScheduleSyncGenerators(projectGraph) {
100
+ if (!projectGraph) {
101
+ // If the project graph is not available, we can't collect and schedule
102
+ // sync generators. The project graph error will be reported separately.
103
+ return;
104
+ }
105
+ log('collect registered sync generators');
106
+ collectAllRegisteredSyncGenerators(projectGraph);
107
+ // a change imply we need to re-run all the generators
108
+ // make sure to schedule all the collected generators
109
+ scheduledGenerators.clear();
110
+ for (const generator of registeredSyncGenerators) {
111
+ scheduledGenerators.add(generator);
112
+ }
113
+ log('scheduling:', [...scheduledGenerators]);
114
+ if (scheduledTimeoutId) {
115
+ // we have a scheduled run already, so we don't need to do anything
116
+ return;
117
+ }
118
+ scheduledTimeoutId = setTimeout(async () => {
119
+ scheduledTimeoutId = undefined;
120
+ if (waitPeriod < 4000) {
121
+ waitPeriod = waitPeriod * 2;
122
+ }
123
+ if (scheduledGenerators.size === 0) {
124
+ // no generators to run
125
+ return;
126
+ }
127
+ const { projects } = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(projectGraph);
128
+ for (const generator of scheduledGenerators) {
129
+ runGenerator(generator, projects);
130
+ }
131
+ await Promise.all(syncGeneratorsCacheResultPromises.values());
132
+ }, waitPeriod);
133
+ }
134
+ async function getCachedRegisteredSyncGenerators() {
135
+ log('get registered sync generators');
136
+ if (!registeredSyncGenerators) {
137
+ log('no registered sync generators, collecting them');
138
+ const { projectGraph } = await (0, project_graph_incremental_recomputation_1.getCachedSerializedProjectGraphPromise)();
139
+ collectAllRegisteredSyncGenerators(projectGraph);
140
+ }
141
+ else {
142
+ log('registered sync generators already collected, returning them');
143
+ }
144
+ return [...registeredSyncGenerators];
145
+ }
146
+ function collectAllRegisteredSyncGenerators(projectGraph) {
147
+ const projectGraphHash = hashProjectGraph(projectGraph);
148
+ if (storedProjectGraphHash !== projectGraphHash) {
149
+ storedProjectGraphHash = projectGraphHash;
150
+ registeredTaskSyncGenerators =
151
+ (0, sync_generators_1.collectRegisteredTaskSyncGenerators)(projectGraph);
152
+ }
153
+ else {
154
+ log('project graph hash is the same, not collecting task sync generators');
155
+ }
156
+ const nxJson = (0, nx_json_1.readNxJson)();
157
+ const nxJsonHash = (0, file_hasher_1.hashArray)(nxJson.sync?.globalGenerators?.sort() ?? []);
158
+ if (storedNxJsonHash !== nxJsonHash) {
159
+ storedNxJsonHash = nxJsonHash;
160
+ registeredGlobalSyncGenerators =
161
+ (0, sync_generators_1.collectRegisteredGlobalSyncGenerators)(nxJson);
162
+ }
163
+ else {
164
+ log('nx.json hash is the same, not collecting global sync generators');
165
+ }
166
+ const generators = new Set([
167
+ ...registeredTaskSyncGenerators,
168
+ ...registeredGlobalSyncGenerators,
169
+ ]);
170
+ if (!registeredSyncGenerators) {
171
+ registeredSyncGenerators = generators;
172
+ return;
173
+ }
174
+ for (const generator of registeredSyncGenerators) {
175
+ if (!generators.has(generator)) {
176
+ registeredSyncGenerators.delete(generator);
177
+ syncGeneratorsCacheResultPromises.delete(generator);
178
+ }
179
+ }
180
+ for (const generator of generators) {
181
+ if (!registeredSyncGenerators.has(generator)) {
182
+ registeredSyncGenerators.add(generator);
183
+ }
184
+ }
185
+ }
186
+ function runGenerator(generator, projects) {
187
+ log('running scheduled generator', generator);
188
+ // remove it from the scheduled set
189
+ scheduledGenerators.delete(generator);
190
+ const tree = new tree_1.FsTree(workspace_root_1.workspaceRoot, false, `running sync generator ${generator}`);
191
+ // run the generator and cache the result
192
+ syncGeneratorsCacheResultPromises.set(generator, (0, sync_generators_1.runSyncGenerator)(tree, generator, projects).then((result) => {
193
+ log(generator, 'changes:', result.changes.map((c) => c.path).join(', '));
194
+ return result;
195
+ }));
196
+ }
197
+ function hashProjectGraph(projectGraph) {
198
+ const stringifiedProjects = Object.entries(projectGraph.nodes)
199
+ .sort(([projectNameA], [projectNameB]) => projectNameA.localeCompare(projectNameB))
200
+ .map(([projectName, projectConfig]) => `${projectName}:${JSON.stringify(projectConfig)}`);
201
+ return (0, file_hasher_1.hashArray)(stringifiedProjects);
202
+ }
@@ -15,20 +15,33 @@ exports.isWindows = (0, os_1.platform)() === 'win32';
15
15
  * See https://nodejs.org/dist/latest-v14.x/docs/api/net.html#net_identifying_paths_for_ipc_connections for a full breakdown
16
16
  * of OS differences between Unix domain sockets and named pipes.
17
17
  */
18
- const getFullOsSocketPath = () => exports.isWindows
19
- ? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)())
20
- : (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)());
18
+ const getFullOsSocketPath = () => {
19
+ const path = (0, path_1.resolve)((0, tmp_dir_1.getDaemonSocketDir)());
20
+ assertValidSocketPath(path);
21
+ return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
22
+ };
21
23
  exports.getFullOsSocketPath = getFullOsSocketPath;
22
24
  const getForkedProcessOsSocketPath = (id) => {
23
25
  let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(), 'fp' + id + '.sock'));
24
- return exports.isWindows ? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)(path) : (0, path_1.resolve)(path);
26
+ assertValidSocketPath(path);
27
+ return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
25
28
  };
26
29
  exports.getForkedProcessOsSocketPath = getForkedProcessOsSocketPath;
27
30
  const getPluginOsSocketPath = (id) => {
28
31
  let path = (0, path_1.resolve)((0, path_1.join)((0, tmp_dir_1.getSocketDir)(true), 'plugin' + id + '.sock'));
29
- return exports.isWindows ? '\\\\.\\pipe\\nx\\' + (0, path_1.resolve)(path) : (0, path_1.resolve)(path);
32
+ assertValidSocketPath(path);
33
+ return exports.isWindows ? '\\\\.\\pipe\\nx\\' + path : path;
30
34
  };
31
35
  exports.getPluginOsSocketPath = getPluginOsSocketPath;
36
+ function assertValidSocketPath(path) {
37
+ if (path.length > 95) {
38
+ throw new Error([
39
+ 'Attempted to open socket that exceeds the maximum socket length.',
40
+ '',
41
+ `Set NX_SOCKET_DIR to a shorter path (e.g. ${exports.isWindows ? '%TMP%/nx-tmp' : '/tmp/nx-tmp'}) to avoid this issue.`,
42
+ ].join('\n'));
43
+ }
44
+ }
32
45
  function killSocketOrPath() {
33
46
  try {
34
47
  (0, fs_1.unlinkSync)((0, exports.getFullOsSocketPath)());
@@ -53,7 +53,8 @@ function socketDirName() {
53
53
  */
54
54
  function getSocketDir(alreadyUnique = false) {
55
55
  try {
56
- const dir = process.env.NX_DAEMON_SOCKET_DIR ??
56
+ const dir = process.env.NX_SOCKET_DIR ??
57
+ process.env.NX_DAEMON_SOCKET_DIR ??
57
58
  (alreadyUnique ? tmp_1.tmpdir : socketDirName());
58
59
  (0, fs_extra_1.ensureDirSync)(dir);
59
60
  return dir;
Binary file
@@ -94,7 +94,7 @@ function addNxCloudOptionsToNxJson(tree, token, directory = '') {
94
94
  });
95
95
  }
96
96
  }
97
- function addNxCloudIdToNxJson(tree, nxCloudId, directory = tree.root) {
97
+ function addNxCloudIdToNxJson(tree, nxCloudId, directory = '') {
98
98
  const nxJsonPath = (0, path_1.join)(directory, 'nx.json');
99
99
  if (tree.exists(nxJsonPath)) {
100
100
  (0, json_1.updateJson)(tree, (0, path_1.join)(directory, 'nx.json'), (nxJson) => {
@@ -5,7 +5,7 @@ import { TargetDependencyConfig } from '../config/workspace-json-project-json';
5
5
  import { NxArgs } from '../utils/command-line-utils';
6
6
  import { LifeCycle } from './life-cycle';
7
7
  import { TasksRunner } from './tasks-runner';
8
- export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], projectGraph: ProjectGraph, { nxJson }: {
8
+ export declare function runCommand(projectsToRun: ProjectGraphProjectNode[], currentProjectGraph: ProjectGraph, { nxJson }: {
9
9
  nxJson: NxJsonConfiguration;
10
10
  }, nxArgs: NxArgs, overrides: any, initiatingProject: string | null, extraTargetDependencies: Record<string, (TargetDependencyConfig | string)[]>, extraOptions: {
11
11
  excludeTaskDependencies: boolean;
@@ -4,16 +4,20 @@ exports.runCommand = runCommand;
4
4
  exports.invokeTasksRunner = invokeTasksRunner;
5
5
  exports.getRunner = getRunner;
6
6
  exports.getRunnerOptions = getRunnerOptions;
7
+ const enquirer_1 = require("enquirer");
8
+ const ora = require("ora");
7
9
  const path_1 = require("path");
8
10
  const nx_json_1 = require("../config/nx-json");
9
11
  const client_1 = require("../daemon/client/client");
10
12
  const create_task_hasher_1 = require("../hasher/create-task-hasher");
11
13
  const hash_task_1 = require("../hasher/hash-task");
14
+ const project_graph_1 = require("../project-graph/project-graph");
12
15
  const fileutils_1 = require("../utils/fileutils");
13
16
  const is_ci_1 = require("../utils/is-ci");
14
17
  const nx_cloud_utils_1 = require("../utils/nx-cloud-utils");
15
18
  const output_1 = require("../utils/output");
16
19
  const params_1 = require("../utils/params");
20
+ const sync_generators_1 = require("../utils/sync-generators");
17
21
  const workspace_root_1 = require("../utils/workspace-root");
18
22
  const create_task_graph_1 = require("./create-task-graph");
19
23
  const life_cycle_1 = require("./life-cycle");
@@ -27,6 +31,7 @@ const task_profiling_life_cycle_1 = require("./life-cycles/task-profiling-life-c
27
31
  const task_timings_life_cycle_1 = require("./life-cycles/task-timings-life-cycle");
28
32
  const task_graph_utils_1 = require("./task-graph-utils");
29
33
  const utils_1 = require("./utils");
34
+ const chalk = require("chalk");
30
35
  async function getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides) {
31
36
  const { runnerOptions } = getRunner(nxArgs, nxJson);
32
37
  const isRunOne = initiatingProject != null;
@@ -90,10 +95,10 @@ function createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies,
90
95
  }
91
96
  return taskGraph;
92
97
  }
93
- async function runCommand(projectsToRun, projectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
98
+ async function runCommand(projectsToRun, currentProjectGraph, { nxJson }, nxArgs, overrides, initiatingProject, extraTargetDependencies, extraOptions) {
94
99
  const status = await (0, params_1.handleErrors)(process.env.NX_VERBOSE_LOGGING === 'true', async () => {
95
100
  const projectNames = projectsToRun.map((t) => t.name);
96
- const taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
101
+ const { projectGraph, taskGraph } = await ensureWorkspaceIsInSyncAndGetGraphs(currentProjectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions);
97
102
  const tasks = Object.values(taskGraph.tasks);
98
103
  const { lifeCycle, renderIsDone } = await getTerminalOutputLifeCycle(initiatingProject, projectNames, tasks, nxArgs, nxJson, overrides);
99
104
  const status = await invokeTasksRunner({
@@ -111,6 +116,119 @@ async function runCommand(projectsToRun, projectGraph, { nxJson }, nxArgs, overr
111
116
  });
112
117
  return status;
113
118
  }
119
+ async function ensureWorkspaceIsInSyncAndGetGraphs(projectGraph, nxJson, projectNames, nxArgs, overrides, extraTargetDependencies, extraOptions) {
120
+ let taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
121
+ if (process.env.NX_ENABLE_SYNC_GENERATORS !== 'true') {
122
+ return { projectGraph, taskGraph };
123
+ }
124
+ // collect unique syncGenerators from the tasks
125
+ const uniqueSyncGenerators = new Set();
126
+ for (const { target } of Object.values(taskGraph.tasks)) {
127
+ const { syncGenerators } = projectGraph.nodes[target.project].data.targets[target.target];
128
+ if (!syncGenerators) {
129
+ continue;
130
+ }
131
+ for (const generator of syncGenerators) {
132
+ uniqueSyncGenerators.add(generator);
133
+ }
134
+ }
135
+ if (!uniqueSyncGenerators.size) {
136
+ // There are no sync generators registered in the tasks to run
137
+ return { projectGraph, taskGraph };
138
+ }
139
+ const syncGenerators = Array.from(uniqueSyncGenerators);
140
+ const results = await (0, sync_generators_1.getSyncGeneratorChanges)(syncGenerators);
141
+ if (!results.length) {
142
+ // There are no changes to sync, workspace is up to date
143
+ return { projectGraph, taskGraph };
144
+ }
145
+ const outOfSyncTitle = 'The workspace is out of sync';
146
+ const resultBodyLines = (0, sync_generators_1.syncGeneratorResultsToMessageLines)(results);
147
+ const fixMessage = 'You can manually run `nx sync` to update your workspace or you can set `sync.applyChanges` to `true` in your `nx.json` to apply the changes automatically when running tasks.';
148
+ const willErrorOnCiMessage = 'Please note that this will be an error on CI.';
149
+ if ((0, is_ci_1.isCI)() || !process.stdout.isTTY) {
150
+ // If the user is running in CI or is running in a non-TTY environment we
151
+ // throw an error to stop the execution of the tasks.
152
+ throw new Error(`${outOfSyncTitle}\n${resultBodyLines.join('\n')}\n${fixMessage}`);
153
+ }
154
+ if (nxJson.sync?.applyChanges === false) {
155
+ // If the user has set `sync.applyChanges` to `false` in their `nx.json`
156
+ // we don't prompt the them and just log a warning informing them that
157
+ // the workspace is out of sync and they have it set to not apply changes
158
+ // automatically.
159
+ output_1.output.warn({
160
+ title: outOfSyncTitle,
161
+ bodyLines: [
162
+ ...resultBodyLines,
163
+ 'Your workspace is set to not apply changes automatically (`sync.applyChanges` is set to `false` in your `nx.json`).',
164
+ willErrorOnCiMessage,
165
+ fixMessage,
166
+ ],
167
+ });
168
+ return { projectGraph, taskGraph };
169
+ }
170
+ output_1.output.warn({
171
+ title: outOfSyncTitle,
172
+ bodyLines: [
173
+ ...resultBodyLines,
174
+ nxJson.sync?.applyChanges === true
175
+ ? 'Proceeding to sync the changes automatically (`sync.applyChanges` is set to `true` in your `nx.json`).'
176
+ : willErrorOnCiMessage,
177
+ ],
178
+ });
179
+ const applyChanges = nxJson.sync?.applyChanges === true ||
180
+ (await promptForApplyingSyncGeneratorChanges());
181
+ if (applyChanges) {
182
+ const spinner = ora('Syncing the workspace...');
183
+ spinner.start();
184
+ // Flush sync generator changes to disk
185
+ await (0, sync_generators_1.flushSyncGeneratorChanges)(results);
186
+ // Re-create project graph and task graph
187
+ projectGraph = await (0, project_graph_1.createProjectGraphAsync)();
188
+ taskGraph = createTaskGraphAndRunValidations(projectGraph, extraTargetDependencies ?? {}, projectNames, nxArgs, overrides, extraOptions);
189
+ if (nxJson.sync?.applyChanges === true) {
190
+ spinner.succeed(`The workspace was synced successfully!
191
+
192
+ Please make sure to commit the changes to your repository or this will error on CI.`);
193
+ }
194
+ else {
195
+ // The user was prompted and we already logged a message about erroring on CI
196
+ // so here we just tell them to commit the changes.
197
+ spinner.succeed(`The workspace was synced successfully!
198
+
199
+ Please make sure to commit the changes to your repository.`);
200
+ }
201
+ }
202
+ else {
203
+ output_1.output.warn({
204
+ title: 'Syncing the workspace was skipped',
205
+ bodyLines: [
206
+ 'This could lead to unexpected results or errors when running tasks.',
207
+ fixMessage,
208
+ ],
209
+ });
210
+ }
211
+ return { projectGraph, taskGraph };
212
+ }
213
+ async function promptForApplyingSyncGeneratorChanges() {
214
+ const promptConfig = {
215
+ name: 'applyChanges',
216
+ type: 'select',
217
+ message: 'Would you like to sync the changes to get your worskpace up to date?',
218
+ choices: [
219
+ {
220
+ name: 'yes',
221
+ message: 'Yes, sync the changes and run the tasks',
222
+ },
223
+ {
224
+ name: 'no',
225
+ message: 'No, run the tasks without syncing the changes',
226
+ },
227
+ ],
228
+ footer: () => chalk.dim('\nYou can skip this prompt by setting the `sync.applyChanges` option in your `nx.json`.'),
229
+ };
230
+ return await (0, enquirer_1.prompt)([promptConfig]).then(({ applyChanges }) => applyChanges === 'yes');
231
+ }
114
232
  function setEnvVarsBasedOnArgs(nxArgs, loadDotEnvFiles) {
115
233
  if (nxArgs.outputStyle == 'stream' ||
116
234
  process.env.NX_BATCH_MODE === 'true' ||
@@ -70,7 +70,7 @@ function splitArgsIntoNxArgsAndOverrides(args, mode, options = { printWarnings:
70
70
  ],
71
71
  });
72
72
  }
73
- // Allow setting base and head via environment variables (lower priority then direct command arguments)
73
+ // Allow setting base and head via environment variables (lower priority than direct command arguments)
74
74
  if (!nxArgs.base && process.env.NX_BASE) {
75
75
  nxArgs.base = process.env.NX_BASE;
76
76
  if (options.printWarnings) {
@@ -27,7 +27,7 @@ function listPlugins(plugins, title) {
27
27
  if (p.projectInference) {
28
28
  capabilities.push('project-inference');
29
29
  }
30
- bodyLines.push(`${chalk.bold(p.name)} (${capabilities.join()})`);
30
+ bodyLines.push(`${chalk.bold(p.name)} ${capabilities.length >= 1 ? `(${capabilities.join()})` : ''}`);
31
31
  }
32
32
  output_1.output.log({
33
33
  title: title,
@@ -0,0 +1,22 @@
1
+ import type { GeneratorCallback } from '../config/misc-interfaces';
2
+ import type { ProjectGraph } from '../config/project-graph';
3
+ import type { ProjectConfiguration } from '../config/workspace-json-project-json';
4
+ import { FsTree, type FileChange, type Tree } from '../generators/tree';
5
+ export type SyncGeneratorResult = void | {
6
+ callback?: GeneratorCallback;
7
+ outOfSyncMessage?: string;
8
+ };
9
+ export type SyncGenerator = (tree: Tree) => SyncGeneratorResult | Promise<SyncGeneratorResult>;
10
+ export type SyncGeneratorChangesResult = {
11
+ changes: FileChange[];
12
+ generatorName: string;
13
+ callback?: GeneratorCallback;
14
+ outOfSyncMessage?: string;
15
+ };
16
+ export declare function getSyncGeneratorChanges(generators: string[]): Promise<SyncGeneratorChangesResult[]>;
17
+ export declare function flushSyncGeneratorChanges(results: SyncGeneratorChangesResult[]): Promise<void>;
18
+ export declare function collectAllRegisteredSyncGenerators(projectGraph: ProjectGraph): Promise<string[]>;
19
+ export declare function runSyncGenerator(tree: FsTree, generatorSpecifier: string, projects: Record<string, ProjectConfiguration>): Promise<SyncGeneratorChangesResult>;
20
+ export declare function collectRegisteredTaskSyncGenerators(projectGraph: ProjectGraph): Set<string>;
21
+ export declare function collectRegisteredGlobalSyncGenerators(nxJson?: import("../config/nx-json").NxJsonConfiguration<string[] | "*">): Set<string>;
22
+ export declare function syncGeneratorResultsToMessageLines(results: SyncGeneratorChangesResult[]): string[];