@joshmossas/nx-cargo 0.6.2 → 0.6.4

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.
package/dist/index.cjs CHANGED
@@ -1,12 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  const devkit = require('@nx/devkit');
4
- const fs = require('node:fs');
5
- const cp = require('node:child_process');
6
- const os = require('node:os');
7
- const path = require('node:path');
8
-
9
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
4
+ const cp = require('child_process');
5
+ const os = require('os');
6
+ const path = require('path');
7
+ const fs = require('fs');
10
8
 
11
9
  function _interopNamespaceCompat(e) {
12
10
  if (e && typeof e === 'object' && 'default' in e) return e;
@@ -20,40 +18,47 @@ function _interopNamespaceCompat(e) {
20
18
  return n;
21
19
  }
22
20
 
23
- const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
24
21
  const cp__namespace = /*#__PURE__*/_interopNamespaceCompat(cp);
25
22
  const os__namespace = /*#__PURE__*/_interopNamespaceCompat(os);
26
23
  const path__namespace = /*#__PURE__*/_interopNamespaceCompat(path);
24
+ const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
27
25
 
28
26
  function createDependencies(_, ctx) {
29
27
  const allDependencies = [];
30
- const processedWorkspaceRoots = /* @__PURE__ */ new Set();
31
- const cargoConfigPaths = Object.values(ctx.projects).map((p) => path__namespace.join(ctx.workspaceRoot, p.root, "Cargo.toml")).filter((p) => fs__default.existsSync(p));
32
- for (const configPath of cargoConfigPaths) {
33
- const configDir = path__namespace.dirname(configPath);
34
- const metadata = getCargoMetadata(configDir);
35
- if (processedWorkspaceRoots.has(metadata.workspace_root)) {
28
+ const seenManifestPaths = /* @__PURE__ */ new Set();
29
+ const sortedManifests = Object.values(ctx.projects).map((project) => {
30
+ const filepath = path__namespace.resolve(ctx.workspaceRoot, project.root, "Cargo.toml");
31
+ const depth = filepath.split(path__namespace.sep).length;
32
+ return { filepath, depth };
33
+ }).filter((manifest) => fs__namespace.existsSync(manifest.filepath)).sort((a, b) => a.depth - b.depth);
34
+ for (const { filepath } of sortedManifests) {
35
+ if (seenManifestPaths.has(filepath)) {
36
36
  continue;
37
37
  }
38
- processedWorkspaceRoots.add(metadata.workspace_root);
39
- const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
40
- allDependencies.push(...workspaceDeps);
38
+ try {
39
+ const metadata = getCargoMetadata(path__namespace.dirname(filepath));
40
+ for (const pkg of metadata.packages) {
41
+ seenManifestPaths.add(path__namespace.resolve(pkg.manifest_path));
42
+ }
43
+ const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
44
+ allDependencies.push(...workspaceDeps);
45
+ } catch (e) {
46
+ console.warn(
47
+ `[nx-rust] Skipping ${filepath} due to error:`,
48
+ e instanceof Error ? e.message : e
49
+ );
50
+ }
41
51
  }
42
52
  return allDependencies;
43
53
  }
44
54
  function processWorkspaceMetadata(ctx, metadata) {
45
- const {
46
- packages,
47
- workspace_members: cargoWsMembers,
48
- resolve: cargoResolve
49
- } = metadata;
55
+ const { packages, resolve } = metadata;
50
56
  const workspacePackages = /* @__PURE__ */ new Map();
51
- for (const id of cargoWsMembers) {
52
- const pkg = packages.find((p) => p.id === id);
53
- if (pkg) workspacePackages.set(id, pkg);
57
+ for (const pkg of packages) {
58
+ workspacePackages.set(pkg.id, pkg);
54
59
  }
55
60
  const nxData = mapCargoProjects(ctx, workspacePackages);
56
- return cargoResolve.nodes.filter(({ id }) => nxData.has(id)).flatMap(({ id: sourceId, dependencies }) => {
61
+ return (resolve?.nodes ?? []).filter(({ id }) => nxData.has(id)).flatMap(({ id: sourceId, dependencies }) => {
57
62
  const sourceProject = nxData.get(sourceId);
58
63
  const cargoPackage = workspacePackages.get(sourceId);
59
64
  const sourceManifest = path__namespace.relative(ctx.workspaceRoot, cargoPackage.manifest_path).replace(/\\/g, "/");
@@ -65,29 +70,16 @@ function processWorkspaceMetadata(ctx, metadata) {
65
70
  }));
66
71
  });
67
72
  }
68
- function getCargoMetadata(cwd) {
69
- const availableMemory = os__namespace.freemem();
70
- const metadata = cp__namespace.execSync("cargo metadata --format-version=1", {
71
- encoding: "utf8",
72
- maxBuffer: availableMemory,
73
- cwd
74
- // Crucial: run in the workspace directory
75
- });
76
- return JSON.parse(metadata);
77
- }
78
73
  function mapCargoProjects(ctx, packages) {
79
- let result = /* @__PURE__ */ new Map();
80
- for (let [cargoId, cargoPackage] of packages) {
81
- if (!cargoPackage.manifest_path) {
82
- throw new Error("Expected cargo package's `manifest_path` to exist");
83
- }
84
- let manifestDir = path__namespace.dirname(cargoPackage.manifest_path);
85
- let projectDir = path__namespace.relative(ctx.workspaceRoot, manifestDir).replace(/\\/g, "/");
86
- let found = Object.entries(ctx.projects).find(
74
+ const result = /* @__PURE__ */ new Map();
75
+ for (const [cargoId, cargoPackage] of packages) {
76
+ const manifestDir = path__namespace.dirname(cargoPackage.manifest_path);
77
+ const projectDir = path__namespace.relative(ctx.workspaceRoot, manifestDir).replace(/\\/g, "/");
78
+ const found = Object.entries(ctx.projects).find(
87
79
  ([, config]) => config.root === projectDir
88
80
  );
89
81
  if (found) {
90
- let [projectName, projectConfig] = found;
82
+ const [projectName, projectConfig] = found;
91
83
  result.set(cargoId, {
92
84
  ...projectConfig,
93
85
  name: projectName
@@ -96,5 +88,14 @@ function mapCargoProjects(ctx, packages) {
96
88
  }
97
89
  return result;
98
90
  }
91
+ function getCargoMetadata(cwd) {
92
+ const availableMemory = os__namespace.freemem();
93
+ const metadata = cp__namespace.execSync("cargo metadata --format-version=1 --no-deps", {
94
+ encoding: "utf8",
95
+ maxBuffer: availableMemory,
96
+ cwd
97
+ });
98
+ return JSON.parse(metadata);
99
+ }
99
100
 
100
101
  exports.createDependencies = createDependencies;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { CreateDependenciesContext, RawProjectGraphDependency } from '@nx/devkit';
2
2
 
3
+ /**
4
+ * Main Nx Dependency Creator
5
+ */
3
6
  declare function createDependencies(_: unknown, ctx: CreateDependenciesContext): RawProjectGraphDependency[];
4
7
 
5
8
  export { createDependencies };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { CreateDependenciesContext, RawProjectGraphDependency } from '@nx/devkit';
2
2
 
3
+ /**
4
+ * Main Nx Dependency Creator
5
+ */
3
6
  declare function createDependencies(_: unknown, ctx: CreateDependenciesContext): RawProjectGraphDependency[];
4
7
 
5
8
  export { createDependencies };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import { CreateDependenciesContext, RawProjectGraphDependency } from '@nx/devkit';
2
2
 
3
+ /**
4
+ * Main Nx Dependency Creator
5
+ */
3
6
  declare function createDependencies(_: unknown, ctx: CreateDependenciesContext): RawProjectGraphDependency[];
4
7
 
5
8
  export { createDependencies };
package/dist/index.mjs CHANGED
@@ -1,38 +1,45 @@
1
1
  import { DependencyType } from '@nx/devkit';
2
- import fs from 'node:fs';
3
- import * as cp from 'node:child_process';
4
- import * as os from 'node:os';
5
- import * as path from 'node:path';
2
+ import * as cp from 'child_process';
3
+ import * as os from 'os';
4
+ import * as path from 'path';
5
+ import * as fs from 'fs';
6
6
 
7
7
  function createDependencies(_, ctx) {
8
8
  const allDependencies = [];
9
- const processedWorkspaceRoots = /* @__PURE__ */ new Set();
10
- const cargoConfigPaths = Object.values(ctx.projects).map((p) => path.join(ctx.workspaceRoot, p.root, "Cargo.toml")).filter((p) => fs.existsSync(p));
11
- for (const configPath of cargoConfigPaths) {
12
- const configDir = path.dirname(configPath);
13
- const metadata = getCargoMetadata(configDir);
14
- if (processedWorkspaceRoots.has(metadata.workspace_root)) {
9
+ const seenManifestPaths = /* @__PURE__ */ new Set();
10
+ const sortedManifests = Object.values(ctx.projects).map((project) => {
11
+ const filepath = path.resolve(ctx.workspaceRoot, project.root, "Cargo.toml");
12
+ const depth = filepath.split(path.sep).length;
13
+ return { filepath, depth };
14
+ }).filter((manifest) => fs.existsSync(manifest.filepath)).sort((a, b) => a.depth - b.depth);
15
+ for (const { filepath } of sortedManifests) {
16
+ if (seenManifestPaths.has(filepath)) {
15
17
  continue;
16
18
  }
17
- processedWorkspaceRoots.add(metadata.workspace_root);
18
- const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
19
- allDependencies.push(...workspaceDeps);
19
+ try {
20
+ const metadata = getCargoMetadata(path.dirname(filepath));
21
+ for (const pkg of metadata.packages) {
22
+ seenManifestPaths.add(path.resolve(pkg.manifest_path));
23
+ }
24
+ const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
25
+ allDependencies.push(...workspaceDeps);
26
+ } catch (e) {
27
+ console.warn(
28
+ `[nx-rust] Skipping ${filepath} due to error:`,
29
+ e instanceof Error ? e.message : e
30
+ );
31
+ }
20
32
  }
21
33
  return allDependencies;
22
34
  }
23
35
  function processWorkspaceMetadata(ctx, metadata) {
24
- const {
25
- packages,
26
- workspace_members: cargoWsMembers,
27
- resolve: cargoResolve
28
- } = metadata;
36
+ const { packages, resolve } = metadata;
29
37
  const workspacePackages = /* @__PURE__ */ new Map();
30
- for (const id of cargoWsMembers) {
31
- const pkg = packages.find((p) => p.id === id);
32
- if (pkg) workspacePackages.set(id, pkg);
38
+ for (const pkg of packages) {
39
+ workspacePackages.set(pkg.id, pkg);
33
40
  }
34
41
  const nxData = mapCargoProjects(ctx, workspacePackages);
35
- return cargoResolve.nodes.filter(({ id }) => nxData.has(id)).flatMap(({ id: sourceId, dependencies }) => {
42
+ return (resolve?.nodes ?? []).filter(({ id }) => nxData.has(id)).flatMap(({ id: sourceId, dependencies }) => {
36
43
  const sourceProject = nxData.get(sourceId);
37
44
  const cargoPackage = workspacePackages.get(sourceId);
38
45
  const sourceManifest = path.relative(ctx.workspaceRoot, cargoPackage.manifest_path).replace(/\\/g, "/");
@@ -44,29 +51,16 @@ function processWorkspaceMetadata(ctx, metadata) {
44
51
  }));
45
52
  });
46
53
  }
47
- function getCargoMetadata(cwd) {
48
- const availableMemory = os.freemem();
49
- const metadata = cp.execSync("cargo metadata --format-version=1", {
50
- encoding: "utf8",
51
- maxBuffer: availableMemory,
52
- cwd
53
- // Crucial: run in the workspace directory
54
- });
55
- return JSON.parse(metadata);
56
- }
57
54
  function mapCargoProjects(ctx, packages) {
58
- let result = /* @__PURE__ */ new Map();
59
- for (let [cargoId, cargoPackage] of packages) {
60
- if (!cargoPackage.manifest_path) {
61
- throw new Error("Expected cargo package's `manifest_path` to exist");
62
- }
63
- let manifestDir = path.dirname(cargoPackage.manifest_path);
64
- let projectDir = path.relative(ctx.workspaceRoot, manifestDir).replace(/\\/g, "/");
65
- let found = Object.entries(ctx.projects).find(
55
+ const result = /* @__PURE__ */ new Map();
56
+ for (const [cargoId, cargoPackage] of packages) {
57
+ const manifestDir = path.dirname(cargoPackage.manifest_path);
58
+ const projectDir = path.relative(ctx.workspaceRoot, manifestDir).replace(/\\/g, "/");
59
+ const found = Object.entries(ctx.projects).find(
66
60
  ([, config]) => config.root === projectDir
67
61
  );
68
62
  if (found) {
69
- let [projectName, projectConfig] = found;
63
+ const [projectName, projectConfig] = found;
70
64
  result.set(cargoId, {
71
65
  ...projectConfig,
72
66
  name: projectName
@@ -75,5 +69,14 @@ function mapCargoProjects(ctx, packages) {
75
69
  }
76
70
  return result;
77
71
  }
72
+ function getCargoMetadata(cwd) {
73
+ const availableMemory = os.freemem();
74
+ const metadata = cp.execSync("cargo metadata --format-version=1 --no-deps", {
75
+ encoding: "utf8",
76
+ maxBuffer: availableMemory,
77
+ cwd
78
+ });
79
+ return JSON.parse(metadata);
80
+ }
78
81
 
79
82
  export { createDependencies };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@joshmossas/nx-cargo",
3
3
  "private": false,
4
- "version": "0.6.2",
4
+ "version": "0.6.4",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.mjs",
7
7
  "repository": {
@@ -4,11 +4,13 @@ import {
4
4
  RawProjectGraphDependency as GraphDependency,
5
5
  DependencyType,
6
6
  } from "@nx/devkit";
7
- import fs from "node:fs";
8
- import * as cp from "node:child_process";
9
- import * as os from "node:os";
10
- import * as path from "node:path";
7
+ import * as cp from "child_process";
8
+ import * as os from "os";
9
+ import * as path from "path";
10
+ import * as fs from "fs";
11
11
 
12
+ /** * Type Definitions for Cargo Metadata
13
+ */
12
14
  type VersionNumber = `${number}.${number}.${number}`;
13
15
  type PackageVersion = `${string}@${VersionNumber}` | VersionNumber;
14
16
  type CargoId = `${"registry" | "path"}+${
@@ -20,109 +22,91 @@ interface CargoPackage {
20
22
  name: string;
21
23
  version: string;
22
24
  id: CargoId;
23
- license: string;
24
- license_file: string | null;
25
- description: string;
26
- source: string | null;
27
- dependencies: CargoDependency[];
28
- targets: unknown; // TODO
29
- features: Record<string, string[]>;
25
+ dependencies: unknown[];
30
26
  manifest_path: string;
31
- metadata: unknown | null; // TODO
32
- publish: unknown | null; // TODO
33
- authors: string[];
34
- categories: string[];
35
- keywords: string[];
36
- readme: string | null;
37
- repository: string | null;
38
- homepage: string | null;
39
- documentation: string | null;
40
- edition: string;
41
- links: unknown | null; // TODO
42
- default_run: unknown | null; // TODO
43
- rust_version: string;
44
- }
45
-
46
- interface CargoDependency {
47
- name: string;
48
- source: string | null;
49
- req: string;
50
- kind: "build" | "dev" | null;
51
- rename: string | null;
52
- optional: boolean;
53
- uses_default_features: boolean;
54
- features: string[];
55
- target: string | null;
56
- registry: string | null;
57
- path?: string;
58
27
  }
59
28
 
60
29
  interface CargoMetadata {
61
30
  packages: CargoPackage[];
62
31
  workspace_members: CargoId[];
63
- workspace_default_members: CargoId[];
64
32
  resolve: {
65
33
  nodes: ResolveNode[];
66
- root: unknown;
67
34
  };
68
- target_directory: string;
69
- version: number;
70
35
  workspace_root: string;
71
- metadata: unknown | null;
72
36
  }
73
37
 
74
38
  interface ResolveNode {
75
39
  id: CargoId;
76
40
  dependencies: CargoId[];
77
41
  }
78
- export function createDependencies(_: unknown, ctx: Context): GraphDependency[] {
79
- const allDependencies: GraphDependency[] = [];
80
- const processedWorkspaceRoots = new Set<string>();
81
42
 
82
- // 1. Identify all potential Cargo workspaces/projects in the Nx graph
83
- const cargoConfigPaths = Object.values(ctx.projects)
84
- .map(p => path.join(ctx.workspaceRoot, p.root, "Cargo.toml"))
85
- .filter(p => fs.existsSync(p));
86
-
87
- for (const configPath of cargoConfigPaths) {
88
- const configDir = path.dirname(configPath);
89
-
90
- // 2. Get metadata for this specific workspace
91
- const metadata = getCargoMetadata(configDir);
43
+ type WithReq<T, K extends keyof T> = Omit<T, K> & {
44
+ [Key in K]-?: Exclude<T[Key], null | undefined>;
45
+ };
92
46
 
93
- // 3. Skip if we've already processed this workspace (via another member)
94
- if (processedWorkspaceRoots.has(metadata.workspace_root)) {
47
+ /**
48
+ * Main Nx Dependency Creator
49
+ */
50
+ export function createDependencies(_: unknown, ctx: Context): GraphDependency[] {
51
+ const allDependencies: GraphDependency[] = [];
52
+ const seenManifestPaths = new Set<string>();
53
+
54
+ // 1. Identify and sort manifests by depth (shallowest first)
55
+ // This ensures we hit workspace roots before hitting their members.
56
+ const sortedManifests = Object.values(ctx.projects)
57
+ .map(project => {
58
+ const filepath = path.resolve(ctx.workspaceRoot, project.root, "Cargo.toml");
59
+ const depth = filepath.split(path.sep).length;
60
+ return { filepath, depth };
61
+ })
62
+ .filter(manifest => fs.existsSync(manifest.filepath))
63
+ .sort((a, b) => a.depth - b.depth);
64
+
65
+ for (const { filepath } of sortedManifests) {
66
+ // 2. Skip if this manifest was already included in a previously processed workspace
67
+ if (seenManifestPaths.has(filepath)) {
95
68
  continue;
96
69
  }
97
- processedWorkspaceRoots.add(metadata.workspace_root);
98
70
 
99
- // 4. Process this workspace's internal dependencies
100
- const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
101
- allDependencies.push(...workspaceDeps);
71
+ try {
72
+ const metadata = getCargoMetadata(path.dirname(filepath));
73
+
74
+ // 3. Mark every package in this metadata as "seen" to avoid redundant calls
75
+ for (const pkg of metadata.packages) {
76
+ seenManifestPaths.add(path.resolve(pkg.manifest_path));
77
+ }
78
+
79
+ // 4. Extract dependencies from this specific workspace/crate
80
+ const workspaceDeps = processWorkspaceMetadata(ctx, metadata);
81
+ allDependencies.push(...workspaceDeps);
82
+ } catch (e) {
83
+ console.warn(
84
+ `[nx-rust] Skipping ${filepath} due to error:`,
85
+ e instanceof Error ? e.message : e
86
+ );
87
+ }
102
88
  }
103
89
 
104
90
  return allDependencies;
105
91
  }
106
92
 
93
+ /**
94
+ * Orchestrates the mapping between Cargo's internal resolve graph and Nx projects
95
+ */
107
96
  function processWorkspaceMetadata(
108
97
  ctx: Context,
109
98
  metadata: CargoMetadata
110
99
  ): GraphDependency[] {
111
- const {
112
- packages,
113
- workspace_members: cargoWsMembers,
114
- resolve: cargoResolve,
115
- } = metadata;
100
+ const { packages, resolve } = metadata;
116
101
 
117
102
  const workspacePackages = new Map<CargoId, CargoPackage>();
118
- for (const id of cargoWsMembers) {
119
- const pkg = packages.find(p => p.id === id);
120
- if (pkg) workspacePackages.set(id, pkg);
103
+ for (const pkg of packages) {
104
+ workspacePackages.set(pkg.id, pkg);
121
105
  }
122
106
 
123
107
  const nxData = mapCargoProjects(ctx, workspacePackages);
124
108
 
125
- return cargoResolve.nodes
109
+ return (resolve?.nodes ?? [])
126
110
  .filter(({ id }) => nxData.has(id))
127
111
  .flatMap(({ id: sourceId, dependencies }) => {
128
112
  const sourceProject = nxData.get(sourceId)!;
@@ -142,42 +126,24 @@ function processWorkspaceMetadata(
142
126
  });
143
127
  }
144
128
 
145
- function getCargoMetadata(cwd: string): CargoMetadata {
146
- const availableMemory = os.freemem();
147
- // Run cargo metadata from the specific directory of the Cargo.toml
148
- const metadata = cp.execSync("cargo metadata --format-version=1", {
149
- encoding: "utf8",
150
- maxBuffer: availableMemory,
151
- cwd: cwd, // Crucial: run in the workspace directory
152
- });
153
-
154
- return JSON.parse(metadata);
155
- }
156
-
157
- type WithReq<T, K extends keyof T> = Omit<T, K> & {
158
- [Key in K]-?: Exclude<T[Key], null | undefined>;
159
- };
160
-
129
+ /**
130
+ * Maps Cargo Packages to Nx Project Configurations based on their root directories
131
+ */
161
132
  function mapCargoProjects(ctx: Context, packages: Map<CargoId, CargoPackage>) {
162
- let result = new Map<CargoId, WithReq<ProjectConfiguration, "name">>();
133
+ const result = new Map<CargoId, WithReq<ProjectConfiguration, "name">>();
163
134
 
164
- for (let [cargoId, cargoPackage] of packages) {
165
- if (!cargoPackage.manifest_path) {
166
- throw new Error("Expected cargo package's `manifest_path` to exist");
167
- }
168
-
169
- let manifestDir = path.dirname(cargoPackage.manifest_path);
170
- let projectDir = path
135
+ for (const [cargoId, cargoPackage] of packages) {
136
+ const manifestDir = path.dirname(cargoPackage.manifest_path);
137
+ const projectDir = path
171
138
  .relative(ctx.workspaceRoot, manifestDir)
172
139
  .replace(/\\/g, "/");
173
140
 
174
- let found = Object.entries(ctx.projects).find(
141
+ const found = Object.entries(ctx.projects).find(
175
142
  ([, config]) => config.root === projectDir
176
143
  );
177
144
 
178
145
  if (found) {
179
- let [projectName, projectConfig] = found;
180
-
146
+ const [projectName, projectConfig] = found;
181
147
  result.set(cargoId, {
182
148
  ...projectConfig,
183
149
  name: projectName,
@@ -187,3 +153,18 @@ function mapCargoProjects(ctx: Context, packages: Map<CargoId, CargoPackage>) {
187
153
 
188
154
  return result;
189
155
  }
156
+
157
+ /**
158
+ * Executes 'cargo metadata'.
159
+ * Uses --no-deps because we only care about internal workspace dependencies.
160
+ */
161
+ function getCargoMetadata(cwd: string): CargoMetadata {
162
+ const availableMemory = os.freemem();
163
+ const metadata = cp.execSync("cargo metadata --format-version=1 --no-deps", {
164
+ encoding: "utf8",
165
+ maxBuffer: availableMemory,
166
+ cwd: cwd,
167
+ });
168
+
169
+ return JSON.parse(metadata);
170
+ }