nx 19.8.10 → 19.8.11

Sign up to get free protection for your applications and to get access to all the features.
package/bin/nx.js CHANGED
@@ -16,6 +16,7 @@ const assert_supported_platform_1 = require("../src/native/assert-supported-plat
16
16
  const perf_hooks_1 = require("perf_hooks");
17
17
  const workspace_context_1 = require("../src/utils/workspace-context");
18
18
  const client_1 = require("../src/daemon/client/client");
19
+ const db_connection_1 = require("../src/utils/db-connection");
19
20
  function main() {
20
21
  if (process.argv[2] !== 'report' &&
21
22
  process.argv[2] !== '--version' &&
@@ -223,4 +224,11 @@ const getLatestVersionOfNx = ((fn) => {
223
224
  let cache = null;
224
225
  return () => cache || (cache = fn());
225
226
  })(_getLatestVersionOfNx);
227
+ function nxCleanup() {
228
+ (0, db_connection_1.removeDbConnections)();
229
+ }
230
+ process.on('exit', nxCleanup);
231
+ process.on('SIGINT', nxCleanup);
232
+ process.on('SIGTERM', nxCleanup);
233
+ process.on('SIGHUP', nxCleanup);
226
234
  main();
@@ -10,14 +10,14 @@ const update_manager_1 = require("../src/nx-cloud/update-manager");
10
10
  const get_cloud_options_1 = require("../src/nx-cloud/utilities/get-cloud-options");
11
11
  const nx_cloud_utils_1 = require("../src/utils/nx-cloud-utils");
12
12
  const nx_json_1 = require("../src/config/nx-json");
13
- const workspace_context_1 = require("../src/utils/workspace-context");
14
13
  const logger_1 = require("../src/utils/logger");
14
+ const workspace_context_1 = require("../src/utils/workspace-context");
15
15
  (async () => {
16
16
  const start = new Date();
17
17
  try {
18
- (0, workspace_context_1.setupWorkspaceContext)(workspace_root_1.workspaceRoot);
19
18
  if (isMainNxPackage() && (0, fileutils_1.fileExists)((0, path_1.join)(workspace_root_1.workspaceRoot, 'nx.json'))) {
20
19
  (0, assert_supported_platform_1.assertSupportedPlatform)();
20
+ (0, workspace_context_1.setupWorkspaceContext)(workspace_root_1.workspaceRoot);
21
21
  try {
22
22
  await client_1.daemonClient.stop();
23
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nx",
3
- "version": "19.8.10",
3
+ "version": "19.8.11",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -67,7 +67,7 @@
67
67
  "yargs-parser": "21.1.1",
68
68
  "node-machine-id": "1.1.12",
69
69
  "ora": "5.3.0",
70
- "@nrwl/tao": "19.8.10"
70
+ "@nrwl/tao": "19.8.11"
71
71
  },
72
72
  "peerDependencies": {
73
73
  "@swc-node/register": "^1.8.0",
@@ -82,16 +82,16 @@
82
82
  }
83
83
  },
84
84
  "optionalDependencies": {
85
- "@nx/nx-darwin-x64": "19.8.10",
86
- "@nx/nx-darwin-arm64": "19.8.10",
87
- "@nx/nx-linux-x64-gnu": "19.8.10",
88
- "@nx/nx-linux-x64-musl": "19.8.10",
89
- "@nx/nx-win32-x64-msvc": "19.8.10",
90
- "@nx/nx-linux-arm64-gnu": "19.8.10",
91
- "@nx/nx-linux-arm64-musl": "19.8.10",
92
- "@nx/nx-linux-arm-gnueabihf": "19.8.10",
93
- "@nx/nx-win32-arm64-msvc": "19.8.10",
94
- "@nx/nx-freebsd-x64": "19.8.10"
85
+ "@nx/nx-darwin-x64": "19.8.11",
86
+ "@nx/nx-darwin-arm64": "19.8.11",
87
+ "@nx/nx-linux-x64-gnu": "19.8.11",
88
+ "@nx/nx-linux-x64-musl": "19.8.11",
89
+ "@nx/nx-win32-x64-msvc": "19.8.11",
90
+ "@nx/nx-linux-arm64-gnu": "19.8.11",
91
+ "@nx/nx-linux-arm64-musl": "19.8.11",
92
+ "@nx/nx-linux-arm-gnueabihf": "19.8.11",
93
+ "@nx/nx-win32-arm64-msvc": "19.8.11",
94
+ "@nx/nx-freebsd-x64": "19.8.11"
95
95
  },
96
96
  "nx-migrations": {
97
97
  "migrations": "./migrations.json",
@@ -15,6 +15,7 @@ const socket_utils_1 = require("../socket-utils");
15
15
  const cache_1 = require("../cache");
16
16
  const plugins_1 = require("./plugins");
17
17
  const error_types_1 = require("../../project-graph/error-types");
18
+ const db_connection_1 = require("../../utils/db-connection");
18
19
  exports.SERVER_INACTIVITY_TIMEOUT_MS = 10800000; // 10800000 ms = 3 hours
19
20
  let watcherInstance;
20
21
  function storeWatcherInstance(instance) {
@@ -50,6 +51,7 @@ async function handleServerProcessTermination({ server, reason, sockets, }) {
50
51
  }
51
52
  (0, cache_1.deleteDaemonJsonProcessCache)();
52
53
  (0, plugins_1.cleanupPlugins)();
54
+ (0, db_connection_1.removeDbConnections)();
53
55
  logger_1.serverLogger.log(`Server stopped because: "${reason}"`);
54
56
  }
55
57
  finally {
@@ -97,6 +97,8 @@ export interface CachedResult {
97
97
  outputsPath: string
98
98
  }
99
99
 
100
+ export declare export function closeDbConnection(connection: ExternalObject<NxDbConnection>): void
101
+
100
102
  export declare export function connectToNxDb(cacheDir: string, nxVersion: string, dbName?: string | undefined | null): ExternalObject<NxDbConnection>
101
103
 
102
104
  export declare export function copy(src: string, dest: string): void
@@ -371,6 +371,7 @@ module.exports.TaskDetails = nativeBinding.TaskDetails
371
371
  module.exports.TaskHasher = nativeBinding.TaskHasher
372
372
  module.exports.Watcher = nativeBinding.Watcher
373
373
  module.exports.WorkspaceContext = nativeBinding.WorkspaceContext
374
+ module.exports.closeDbConnection = nativeBinding.closeDbConnection
374
375
  module.exports.connectToNxDb = nativeBinding.connectToNxDb
375
376
  module.exports.copy = nativeBinding.copy
376
377
  module.exports.EventType = nativeBinding.EventType
Binary file
@@ -21,9 +21,5 @@ export type CreateNodesResultWithContext = CreateNodesResult & {
21
21
  pluginName: string;
22
22
  };
23
23
  export type NormalizedPlugin = NxPluginV2 & Pick<NxPluginV1, 'processProjectGraph'>;
24
- export declare const nxPluginCache: Map<unknown, [
25
- Promise<LoadedNxPlugin>,
26
- () => void
27
- ]>;
28
24
  export declare function loadNxPlugins(plugins: PluginConfiguration[], root?: string): Promise<readonly [LoadedNxPlugin[], () => void]>;
29
25
  export declare function getDefaultPlugins(root: string): Promise<string[]>;
@@ -2,7 +2,7 @@
2
2
  // This file contains the bits and bobs of the internal API for loading and interacting with Nx plugins.
3
3
  // For the public API, used by plugin authors, see `./public-api.ts`.
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
- exports.nxPluginCache = exports.LoadedNxPlugin = void 0;
5
+ exports.LoadedNxPlugin = void 0;
6
6
  exports.loadNxPlugins = loadNxPlugins;
7
7
  exports.getDefaultPlugins = getDefaultPlugins;
8
8
  const path_1 = require("path");
@@ -66,11 +66,6 @@ class LoadedNxPlugin {
66
66
  }
67
67
  }
68
68
  exports.LoadedNxPlugin = LoadedNxPlugin;
69
- // Short lived cache (cleared between cmd runs)
70
- // holding resolved nx plugin objects.
71
- // Allows loaded plugins to not be reloaded when
72
- // referenced multiple times.
73
- exports.nxPluginCache = new Map();
74
69
  function isIsolationEnabled() {
75
70
  // Explicitly enabled, regardless of further conditions
76
71
  if (process.env.NX_ISOLATE_PLUGINS === 'true') {
@@ -106,11 +106,7 @@ export interface PluginWorkerProcessProjectGraphResult {
106
106
  tx: string;
107
107
  };
108
108
  }
109
- export interface PluginWorkerShutdownMessage {
110
- type: 'shutdown';
111
- payload: {};
112
- }
113
- export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerShutdownMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage | PluginCreateMetadataMessage;
109
+ export type PluginWorkerMessage = PluginWorkerLoadMessage | PluginWorkerCreateNodesMessage | PluginCreateDependenciesMessage | PluginWorkerProcessProjectGraphMessage | PluginCreateMetadataMessage;
114
110
  export type PluginWorkerResult = PluginWorkerLoadResult | PluginWorkerCreateNodesResult | PluginCreateDependenciesResult | PluginWorkerProcessProjectGraphResult | PluginCreateMetadataResult;
115
111
  export declare function isPluginWorkerMessage(message: Serializable): message is PluginWorkerMessage;
116
112
  export declare function isPluginWorkerResult(message: Serializable): message is PluginWorkerResult;
@@ -4,12 +4,8 @@ exports.loadRemoteNxPlugin = loadRemoteNxPlugin;
4
4
  const child_process_1 = require("child_process");
5
5
  const path = require("path");
6
6
  const net_1 = require("net");
7
- // TODO (@AgentEnder): After scoped verbose logging is implemented, re-add verbose logs here.
8
- // import { logger } from '../../utils/logger';
9
- const internal_api_1 = require("../internal-api");
10
7
  const socket_utils_1 = require("../../../daemon/socket-utils");
11
8
  const consume_messages_from_socket_1 = require("../../../utils/consume-messages-from-socket");
12
- const exit_codes_1 = require("../../../utils/exit-codes");
13
9
  const messaging_1 = require("./messaging");
14
10
  const cleanupFunctions = new Set();
15
11
  const pluginNames = new Map();
@@ -29,7 +25,6 @@ async function loadRemoteNxPlugin(plugin, root) {
29
25
  const exitHandler = createWorkerExitHandler(worker, pendingPromises);
30
26
  const cleanupFunction = () => {
31
27
  worker.off('exit', exitHandler);
32
- shutdownPluginWorker(socket);
33
28
  socket.destroy();
34
29
  nxPluginWorkerCache.delete(cacheKey);
35
30
  };
@@ -55,9 +50,6 @@ async function loadRemoteNxPlugin(plugin, root) {
55
50
  nxPluginWorkerCache.set(cacheKey, pluginPromise);
56
51
  return [pluginPromise, cleanupFunction];
57
52
  }
58
- function shutdownPluginWorker(socket) {
59
- (0, messaging_1.sendMessageOverSocket)(socket, { type: 'shutdown', payload: {} });
60
- }
61
53
  /**
62
54
  * Creates a message handler for the given worker.
63
55
  * @param worker Instance of plugin-worker
@@ -195,20 +187,6 @@ function createWorkerExitHandler(worker, pendingPromises) {
195
187
  }
196
188
  };
197
189
  }
198
- let cleanedUp = false;
199
- const exitHandler = () => {
200
- internal_api_1.nxPluginCache.clear();
201
- for (const fn of cleanupFunctions) {
202
- fn();
203
- }
204
- cleanedUp = true;
205
- };
206
- process.on('exit', exitHandler);
207
- process.on('SIGINT', () => {
208
- exitHandler();
209
- process.exit((0, exit_codes_1.signalToCode)('SIGINT'));
210
- });
211
- process.on('SIGTERM', exitHandler);
212
190
  function registerPendingPromise(tx, pending, callback, context) {
213
191
  let resolver, rejector, timeout;
214
192
  const promise = new Promise((res, rej) => {
@@ -49,21 +49,6 @@ const server = (0, net_1.createServer)((socket) => {
49
49
  };
50
50
  }
51
51
  },
52
- shutdown: async () => {
53
- // Stops accepting new connections, but existing connections are
54
- // not closed immediately.
55
- server.close(() => {
56
- try {
57
- (0, fs_1.unlinkSync)(socketPath);
58
- }
59
- catch (e) { }
60
- process.exit(0);
61
- });
62
- // Closes existing connection.
63
- socket.end();
64
- // Destroys the socket once it's fully closed.
65
- socket.destroySoon();
66
- },
67
52
  createNodes: async ({ configFiles, context, tx }) => {
68
53
  try {
69
54
  const result = await plugin.createNodes[1](configFiles, context);
@@ -142,6 +127,22 @@ const server = (0, net_1.createServer)((socket) => {
142
127
  },
143
128
  });
144
129
  }));
130
+ // There should only ever be one host -> worker connection
131
+ // since the worker is spawned per host process. As such,
132
+ // we can safely close the worker when the host disconnects.
133
+ socket.on('end', () => {
134
+ // Stops accepting new connections, but existing connections are
135
+ // not closed immediately.
136
+ server.close(() => {
137
+ try {
138
+ (0, fs_1.unlinkSync)(socketPath);
139
+ }
140
+ catch (e) { }
141
+ process.exit(0);
142
+ });
143
+ // Destroys the socket once it's fully closed.
144
+ socket.destroySoon();
145
+ });
145
146
  });
146
147
  server.listen(socketPath);
147
148
  const exitHandler = (exitCode) => () => {
@@ -253,8 +253,10 @@ plugins) {
253
253
  else {
254
254
  errorBodyLines.push(` - ${e.message}`);
255
255
  }
256
- const innerStackTrace = ' ' + e.stack.split('\n').join('\n ');
257
- errorBodyLines.push(innerStackTrace);
256
+ if (e.stack) {
257
+ const innerStackTrace = ' ' + e.stack.split('\n')?.join('\n ');
258
+ errorBodyLines.push(innerStackTrace);
259
+ }
258
260
  }
259
261
  error.stack = errorBodyLines.join('\n');
260
262
  // This represents a single plugin erroring out with a hard error.
@@ -22,22 +22,19 @@ export declare class ProcessTasks {
22
22
  createTask(id: string, project: ProjectGraphProjectNode, target: string, resolvedConfiguration: string | undefined, overrides: Object): Task;
23
23
  resolveConfiguration(project: ProjectGraphProjectNode, target: string, configuration: string | undefined): string;
24
24
  getId(project: string, target: string, configuration: string | undefined): string;
25
- /**
26
- * this function is used to get the non dummy dependencies of a task recursively
27
- * For example, when we have the following dependencies:
28
- * {
29
- * 'app1:compile': [ 'app2:__nx_dummy_task__' ],
30
- * 'app2:__nx_dummy_task__': [ 'app3:__nx_dummy_task__' ],
31
- * 'app3:__nx_dummy_task__': [ 'app4:precompile' ],
32
- * 'app4:precompile': []
33
- * }
34
- * getNonDummyDeps('app1:compile') will return ['app1:compile']
35
- * getNonDummyDeps('app2:__nx_dummy_task__') will return ['app4:precompile']
36
- * getNonDummyDeps('app3:__nx_dummy_task__') will return ['app4:precompile']
37
- * getNonDummyDeps('app4:precompile') will return ['app4:precompile']
38
- */
39
- private getNonDummyDeps;
40
- private filterDummyTasks;
41
25
  }
42
26
  export declare function createTaskGraph(projectGraph: ProjectGraph, extraTargetDependencies: TargetDependencies, projectNames: string[], targets: string[], configuration: string | undefined, overrides: Object, excludeTaskDependencies?: boolean): TaskGraph;
43
27
  export declare function mapTargetDefaultsToDependencies(defaults: TargetDefaults | undefined): TargetDependencies;
28
+ /**
29
+ * This function is used to filter out the dummy tasks from the dependencies
30
+ * It will manipulate the dependencies object in place
31
+ */
32
+ export declare function filterDummyTasks(dependencies: {
33
+ [k: string]: string[];
34
+ }): void;
35
+ /**
36
+ * this function is used to get the non dummy dependencies of a task recursively
37
+ */
38
+ export declare function getNonDummyDeps(currentTask: string, dependencies: {
39
+ [k: string]: string[];
40
+ }, cycles?: Set<string>, seen?: Set<string>): string[];
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProcessTasks = void 0;
4
4
  exports.createTaskGraph = createTaskGraph;
5
5
  exports.mapTargetDefaultsToDependencies = mapTargetDefaultsToDependencies;
6
+ exports.filterDummyTasks = filterDummyTasks;
7
+ exports.getNonDummyDeps = getNonDummyDeps;
6
8
  const utils_1 = require("./utils");
7
9
  const project_graph_utils_1 = require("../utils/project-graph-utils");
8
10
  const output_1 = require("../utils/output");
@@ -54,7 +56,7 @@ class ProcessTasks {
54
56
  this.dependencies[d] = this.dependencies[d].filter((dd) => !!initialTasks[dd]);
55
57
  }
56
58
  }
57
- this.filterDummyTasks();
59
+ filterDummyTasks(this.dependencies);
58
60
  for (const taskId of Object.keys(this.dependencies)) {
59
61
  if (this.dependencies[taskId].length > 0) {
60
62
  this.dependencies[taskId] = [
@@ -138,7 +140,7 @@ class ProcessTasks {
138
140
  }
139
141
  }
140
142
  else {
141
- const dummyId = this.getId(depProject.name, DUMMY_TASK_TARGET, undefined);
143
+ const dummyId = this.getId(depProject.name, task.target.target + DUMMY_TASK_TARGET, undefined);
142
144
  this.dependencies[task.id].push(dummyId);
143
145
  this.dependencies[dummyId] ??= [];
144
146
  const noopTask = this.createDummyTask(dummyId, task);
@@ -189,52 +191,6 @@ class ProcessTasks {
189
191
  }
190
192
  return id;
191
193
  }
192
- /**
193
- * this function is used to get the non dummy dependencies of a task recursively
194
- * For example, when we have the following dependencies:
195
- * {
196
- * 'app1:compile': [ 'app2:__nx_dummy_task__' ],
197
- * 'app2:__nx_dummy_task__': [ 'app3:__nx_dummy_task__' ],
198
- * 'app3:__nx_dummy_task__': [ 'app4:precompile' ],
199
- * 'app4:precompile': []
200
- * }
201
- * getNonDummyDeps('app1:compile') will return ['app1:compile']
202
- * getNonDummyDeps('app2:__nx_dummy_task__') will return ['app4:precompile']
203
- * getNonDummyDeps('app3:__nx_dummy_task__') will return ['app4:precompile']
204
- * getNonDummyDeps('app4:precompile') will return ['app4:precompile']
205
- */
206
- getNonDummyDeps(currentTask, originalTask, cycle) {
207
- if (currentTask === originalTask) {
208
- return [];
209
- }
210
- else if (currentTask.endsWith(DUMMY_TASK_TARGET)) {
211
- if (cycle?.length && cycle?.includes(currentTask)) {
212
- return [];
213
- }
214
- // if not a cycle, recursively get the non dummy dependencies
215
- return (this.dependencies[currentTask]?.flatMap((dep) => this.getNonDummyDeps(dep, originalTask, cycle)) ?? []);
216
- }
217
- else {
218
- return [currentTask];
219
- }
220
- }
221
- filterDummyTasks() {
222
- const cycle = (0, task_graph_utils_1.findCycle)({ dependencies: this.dependencies });
223
- for (const [key, deps] of Object.entries(this.dependencies)) {
224
- if (!key.endsWith(DUMMY_TASK_TARGET)) {
225
- const normalizedDeps = [];
226
- for (const dep of deps) {
227
- normalizedDeps.push(...this.getNonDummyDeps(dep, key, cycle));
228
- }
229
- this.dependencies[key] = normalizedDeps;
230
- }
231
- }
232
- for (const key of Object.keys(this.dependencies)) {
233
- if (key.endsWith(DUMMY_TASK_TARGET)) {
234
- delete this.dependencies[key];
235
- }
236
- }
237
- }
238
194
  }
239
195
  exports.ProcessTasks = ProcessTasks;
240
196
  function createTaskGraph(projectGraph, extraTargetDependencies, projectNames, targets, configuration, overrides, excludeTaskDependencies = false) {
@@ -268,3 +224,43 @@ function interpolateOverrides(args, projectName, project) {
268
224
  });
269
225
  return interpolatedArgs;
270
226
  }
227
+ /**
228
+ * This function is used to filter out the dummy tasks from the dependencies
229
+ * It will manipulate the dependencies object in place
230
+ */
231
+ function filterDummyTasks(dependencies) {
232
+ const cycles = (0, task_graph_utils_1.findCycles)({ dependencies });
233
+ for (const [key, deps] of Object.entries(dependencies)) {
234
+ if (!key.endsWith(DUMMY_TASK_TARGET)) {
235
+ const normalizedDeps = [];
236
+ for (const dep of deps) {
237
+ normalizedDeps.push(...getNonDummyDeps(dep, dependencies, cycles, new Set([key])));
238
+ }
239
+ dependencies[key] = normalizedDeps;
240
+ }
241
+ }
242
+ for (const key of Object.keys(dependencies)) {
243
+ if (key.endsWith(DUMMY_TASK_TARGET)) {
244
+ delete dependencies[key];
245
+ }
246
+ }
247
+ }
248
+ /**
249
+ * this function is used to get the non dummy dependencies of a task recursively
250
+ */
251
+ function getNonDummyDeps(currentTask, dependencies, cycles, seen = new Set()) {
252
+ if (seen.has(currentTask)) {
253
+ return [];
254
+ }
255
+ seen.add(currentTask);
256
+ if (currentTask.endsWith(DUMMY_TASK_TARGET)) {
257
+ if (cycles?.has(currentTask)) {
258
+ return [];
259
+ }
260
+ // if not a cycle, recursively get the non dummy dependencies
261
+ return (dependencies[currentTask]?.flatMap((dep) => getNonDummyDeps(dep, dependencies, cycles, seen)) ?? []);
262
+ }
263
+ else {
264
+ return [currentTask];
265
+ }
266
+ }
@@ -1,8 +1,19 @@
1
1
  import { ProjectGraph } from '../config/project-graph';
2
2
  import { TaskGraph } from '../config/task-graph';
3
+ /**
4
+ * This function finds a cycle in the graph.
5
+ * @returns the first cycle found, or null if no cycle is found.
6
+ */
3
7
  export declare function findCycle(graph: {
4
8
  dependencies: Record<string, string[]>;
5
9
  }): string[] | null;
10
+ /**
11
+ * This function finds all cycles in the graph.
12
+ * @returns a list of unique task ids in all cycles found, or null if no cycle is found.
13
+ */
14
+ export declare function findCycles(graph: {
15
+ dependencies: Record<string, string[]>;
16
+ }): Set<string> | null;
6
17
  export declare function makeAcyclic(graph: {
7
18
  roots: string[];
8
19
  dependencies: Record<string, string[]>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findCycle = findCycle;
4
+ exports.findCycles = findCycles;
4
5
  exports.makeAcyclic = makeAcyclic;
5
6
  exports.validateNoAtomizedTasks = validateNoAtomizedTasks;
6
7
  const output_1 = require("../utils/output");
@@ -17,6 +18,10 @@ function _findCycle(graph, id, visited, path) {
17
18
  }
18
19
  return null;
19
20
  }
21
+ /**
22
+ * This function finds a cycle in the graph.
23
+ * @returns the first cycle found, or null if no cycle is found.
24
+ */
20
25
  function findCycle(graph) {
21
26
  const visited = {};
22
27
  for (const t of Object.keys(graph.dependencies)) {
@@ -29,6 +34,24 @@ function findCycle(graph) {
29
34
  }
30
35
  return null;
31
36
  }
37
+ /**
38
+ * This function finds all cycles in the graph.
39
+ * @returns a list of unique task ids in all cycles found, or null if no cycle is found.
40
+ */
41
+ function findCycles(graph) {
42
+ const visited = {};
43
+ const cycles = new Set();
44
+ for (const t of Object.keys(graph.dependencies)) {
45
+ visited[t] = false;
46
+ }
47
+ for (const t of Object.keys(graph.dependencies)) {
48
+ const cycle = _findCycle(graph, t, visited, [t]);
49
+ if (cycle) {
50
+ cycle.forEach((t) => cycles.add(t));
51
+ }
52
+ }
53
+ return cycles.size ? cycles : null;
54
+ }
32
55
  function _makeAcyclic(graph, id, visited, path) {
33
56
  if (visited[id])
34
57
  return;
@@ -3,3 +3,4 @@ export declare function getDbConnection(opts?: {
3
3
  directory?: string;
4
4
  dbName?: string;
5
5
  }): ExternalObject<NxDbConnection>;
6
+ export declare function removeDbConnections(): void;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDbConnection = getDbConnection;
4
+ exports.removeDbConnections = removeDbConnections;
4
5
  const native_1 = require("../native");
5
6
  const cache_directory_1 = require("./cache-directory");
6
7
  const package_json_1 = require("../../package.json");
@@ -11,6 +12,12 @@ function getDbConnection(opts = {}) {
11
12
  const connection = getEntryOrSet(dbConnectionMap, key, () => (0, native_1.connectToNxDb)(opts.directory, package_json_1.version, opts.dbName));
12
13
  return connection;
13
14
  }
15
+ function removeDbConnections() {
16
+ for (const connection of dbConnectionMap.values()) {
17
+ (0, native_1.closeDbConnection)(connection);
18
+ }
19
+ dbConnectionMap.clear();
20
+ }
14
21
  function getEntryOrSet(map, key, defaultValue) {
15
22
  const existing = map.get(key);
16
23
  if (existing) {