@nx/dotnet 0.0.1 → 22.0.0-beta.9

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 (78) hide show
  1. package/README.md +117 -4
  2. package/README.md__tmpl__ +70 -0
  3. package/dist/analyzer/analyzer-client.d.ts +39 -0
  4. package/dist/analyzer/analyzer-client.d.ts.map +1 -0
  5. package/dist/analyzer/analyzer-client.js +227 -0
  6. package/dist/generators/init/init.d.ts +7 -0
  7. package/dist/generators/init/init.d.ts.map +1 -0
  8. package/dist/generators/init/init.js +107 -0
  9. package/dist/generators/init/schema.d.ts +6 -0
  10. package/dist/generators/init/schema.json +34 -0
  11. package/dist/index.d.ts +3 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +4 -0
  14. package/dist/lib/Microsoft.Build.Locator.dll +0 -0
  15. package/dist/lib/MsbuildAnalyzer +0 -0
  16. package/dist/lib/MsbuildAnalyzer.deps.json +476 -0
  17. package/dist/lib/MsbuildAnalyzer.dll +0 -0
  18. package/dist/lib/MsbuildAnalyzer.dll.config +629 -0
  19. package/dist/lib/MsbuildAnalyzer.pdb +0 -0
  20. package/dist/lib/MsbuildAnalyzer.runtimeconfig.json +14 -0
  21. package/dist/plugin.d.ts +1 -1
  22. package/dist/plugin.d.ts.map +1 -1
  23. package/dist/plugin.js +3 -2
  24. package/dist/plugins/create-dependencies.d.ts +4 -0
  25. package/dist/plugins/create-dependencies.d.ts.map +1 -0
  26. package/dist/plugins/create-dependencies.js +47 -0
  27. package/dist/{src/plugins/plugin.d.ts → plugins/create-nodes.d.ts} +2 -3
  28. package/dist/plugins/create-nodes.d.ts.map +1 -0
  29. package/dist/plugins/create-nodes.js +48 -0
  30. package/dist/plugins/plugin.d.ts +5 -0
  31. package/dist/plugins/plugin.d.ts.map +1 -0
  32. package/dist/plugins/plugin.js +14 -0
  33. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  34. package/dist/utils/cache.d.ts.map +1 -0
  35. package/dist/utils/has-dotnet-plugin.d.ts +3 -0
  36. package/dist/utils/has-dotnet-plugin.d.ts.map +1 -0
  37. package/dist/utils/has-dotnet-plugin.js +8 -0
  38. package/dist/utils/versions.d.ts +2 -0
  39. package/dist/utils/versions.d.ts.map +1 -0
  40. package/dist/utils/versions.js +5 -0
  41. package/generators.json +10 -0
  42. package/migrations.json +4 -0
  43. package/package.json +48 -59
  44. package/dist/package.json +0 -84
  45. package/dist/src/index.d.ts +0 -2
  46. package/dist/src/index.d.ts.map +0 -1
  47. package/dist/src/index.js +0 -7
  48. package/dist/src/plugins/plugin.d.ts.map +0 -1
  49. package/dist/src/plugins/plugin.js +0 -130
  50. package/dist/src/utils/cache.d.ts.map +0 -1
  51. package/dist/src/utils/dependency-detection.d.ts +0 -5
  52. package/dist/src/utils/dependency-detection.d.ts.map +0 -1
  53. package/dist/src/utils/dependency-detection.js +0 -58
  54. package/dist/src/utils/dotnet-cli.d.ts +0 -9
  55. package/dist/src/utils/dotnet-cli.d.ts.map +0 -1
  56. package/dist/src/utils/dotnet-cli.js +0 -39
  57. package/dist/src/utils/dotnet-project-parser.d.ts +0 -13
  58. package/dist/src/utils/dotnet-project-parser.d.ts.map +0 -1
  59. package/dist/src/utils/dotnet-project-parser.js +0 -83
  60. package/dist/src/utils/logger.d.ts +0 -3
  61. package/dist/src/utils/logger.d.ts.map +0 -1
  62. package/dist/src/utils/logger.js +0 -24
  63. package/dist/src/utils/target-builder.d.ts +0 -12
  64. package/dist/src/utils/target-builder.d.ts.map +0 -1
  65. package/dist/src/utils/target-builder.js +0 -525
  66. package/plugin.ts +0 -5
  67. package/src/index.ts +0 -6
  68. package/src/plugins/plugin.ts +0 -230
  69. package/src/utils/cache.ts +0 -19
  70. package/src/utils/dependency-detection.ts +0 -84
  71. package/src/utils/dotnet-cli.ts +0 -52
  72. package/src/utils/dotnet-project-parser.ts +0 -105
  73. package/src/utils/logger.ts +0 -24
  74. package/src/utils/target-builder.ts +0 -657
  75. package/tsconfig.json +0 -16
  76. package/tsconfig.lib.json +0 -21
  77. /package/dist/{src/utils → utils}/cache.d.ts +0 -0
  78. /package/dist/{src/utils → utils}/cache.js +0 -0
package/README.md CHANGED
@@ -1,7 +1,120 @@
1
- # nx-plugin
1
+ <p style="text-align: center;">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
4
+ <img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
5
+ </picture>
6
+ </p>
2
7
 
3
- This library was generated with [Nx](https://nx.dev).
8
+ <div style="text-align: center;">
4
9
 
5
- ## Building
10
+ [![CircleCI](https://circleci.com/gh/nrwl/nx.svg?style=svg)](https://circleci.com/gh/nrwl/nx)
11
+ [![License](https://img.shields.io/npm/l/@nx/workspace.svg?style=flat-square)]()
12
+ [![NPM Version](https://badge.fury.io/js/nx.svg)](https://www.npmjs.com/package/nx)
13
+ [![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)]()
14
+ [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
15
+ [![Join the chat at https://gitter.im/nrwl-nx/community](https://badges.gitter.im/nrwl-nx/community.svg)](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
16
+ [![Join us on the Official Nx Discord Server](https://img.shields.io/discord/1143497901675401286?label=discord)](https://go.nx.dev/community)
17
+
18
+ </div>
19
+
20
+
21
+ <hr>
22
+
23
+ # Nx: Smart Repos · Fast Builds
24
+
25
+ Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
26
+
27
+ ## Build .NET with Nx
28
+
29
+ The goal of `@nx/dotnet` is to make it easy and straightforward to build .NET applications in an Nx workspace. It provides intelligent project graph analysis, automatic dependency detection, and smart target configuration using MSBuild.
30
+
31
+ ### Getting Started
32
+
33
+ #### Step 1: Add the .NET plugin to your Nx workspace
34
+
35
+ ```bash
36
+ nx add @nx/dotnet
37
+ ```
38
+
39
+ #### Step 2: Configure the plugin in your `nx.json`
40
+
41
+ ```json
42
+ {
43
+ "plugins": ["@nx/dotnet"]
44
+ }
45
+ ```
46
+
47
+ #### Step 3: Create your .NET projects
48
+
49
+ ```bash
50
+ # Create a console application
51
+ dotnet new console -n MyApp
52
+
53
+ # Create a class library
54
+ dotnet new classlib -n MyLibrary
55
+
56
+ # Create a test project
57
+ dotnet new xunit -n MyApp.Tests
58
+ ```
59
+
60
+ The plugin will automatically detect your .NET projects and configure appropriate Nx targets.
61
+
62
+ #### Step 4: Run Build, Test, and other commands
63
+
64
+ ```bash
65
+ # Build a project
66
+ nx build my-app
67
+
68
+ # Run tests
69
+ nx test my-app-tests
70
+
71
+ # Build with Release configuration
72
+ nx build my-app --configuration Release
73
+
74
+ # Create a NuGet package
75
+ nx pack my-library
76
+
77
+ # Publish an application
78
+ nx publish my-app
79
+ ```
80
+
81
+ ## Getting Started
82
+
83
+ ### Creating an Nx Workspace
84
+
85
+ **Using `npx`**
86
+
87
+ ```bash
88
+ npx create-nx-workspace
89
+ ```
90
+
91
+ **Using `npm init`**
92
+
93
+ ```bash
94
+ npm init nx-workspace
95
+ ```
96
+
97
+ **Using `yarn create`**
98
+
99
+ ```bash
100
+ yarn create nx-workspace
101
+ ```
102
+
103
+ ### Adding Nx to an Existing Repository
104
+
105
+ Run:
106
+
107
+ ```bash
108
+ npx nx@latest init
109
+ ```
110
+
111
+ ## Documentation & Resources
112
+
113
+ - [Nx.Dev: Documentation, Guides, Tutorials](https://nx.dev)
114
+ - [Intro to Nx](https://nx.dev/getting-started/intro)
115
+ - [Official Nx YouTube Channel](https://www.youtube.com/@NxDevtools)
116
+ - [Blog Posts About Nx](https://nx.dev/blog)
117
+
118
+ <p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
119
+ width="100%" alt="Nx - Smart Repos · Fast Builds"></a></p>
6
120
 
7
- Run `nx build nx-plugin` to build the library.
@@ -0,0 +1,70 @@
1
+ <p style="text-align: center;">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-dark.svg">
4
+ <img alt="Nx - Smart Repos · Fast Builds" src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-light.svg" width="100%">
5
+ </picture>
6
+ </p>
7
+
8
+ {{links}}
9
+
10
+ <hr>
11
+
12
+ # Nx: Smart Repos · Fast Builds
13
+
14
+ Get to green PRs in half the time. Nx optimizes your builds, scales your CI, and fixes failed PRs. Built for developers and AI agents.
15
+
16
+ ## Build .NET with Nx
17
+
18
+ The goal of `@nx/dotnet` is to make it easy and straightforward to build .NET applications in an Nx workspace. It provides intelligent project graph analysis, automatic dependency detection, and smart target configuration using MSBuild.
19
+
20
+ ### Getting Started
21
+
22
+ #### Step 1: Add the .NET plugin to your Nx workspace
23
+
24
+ ```bash
25
+ nx add @nx/dotnet
26
+ ```
27
+
28
+ #### Step 2: Configure the plugin in your `nx.json`
29
+
30
+ ```json
31
+ {
32
+ "plugins": ["@nx/dotnet"]
33
+ }
34
+ ```
35
+
36
+ #### Step 3: Create your .NET projects
37
+
38
+ ```bash
39
+ # Create a console application
40
+ dotnet new console -n MyApp
41
+
42
+ # Create a class library
43
+ dotnet new classlib -n MyLibrary
44
+
45
+ # Create a test project
46
+ dotnet new xunit -n MyApp.Tests
47
+ ```
48
+
49
+ The plugin will automatically detect your .NET projects and configure appropriate Nx targets.
50
+
51
+ #### Step 4: Run Build, Test, and other commands
52
+
53
+ ```bash
54
+ # Build a project
55
+ nx build my-app
56
+
57
+ # Run tests
58
+ nx test my-app-tests
59
+
60
+ # Build with Release configuration
61
+ nx build my-app --configuration Release
62
+
63
+ # Create a NuGet package
64
+ nx pack my-library
65
+
66
+ # Publish an application
67
+ nx publish my-app
68
+ ```
69
+
70
+ {{content}}
@@ -0,0 +1,39 @@
1
+ import { ProjectConfiguration } from '@nx/devkit';
2
+ export interface AnalysisSuccessResult {
3
+ nodesByFile: Record<string, ProjectConfiguration>;
4
+ referencesByRoot: Record<string, {
5
+ refs: string[];
6
+ sourceConfigFile: string;
7
+ }>;
8
+ }
9
+ export interface AnalysisErrorResult {
10
+ error: Error;
11
+ }
12
+ export type AnalysisResult = AnalysisSuccessResult | AnalysisErrorResult;
13
+ export interface DotNetPluginOptions {
14
+ buildTargetName?: string;
15
+ testTargetName?: string;
16
+ cleanTargetName?: string;
17
+ restoreTargetName?: string;
18
+ publishTargetName?: string;
19
+ packTargetName?: string;
20
+ }
21
+ /**
22
+ * Get project analysis results for the given project files.
23
+ * Results are cached based on the content hash of all project files.
24
+ * This should be called by createNodes to populate the cache.
25
+ */
26
+ export declare function analyzeProjects(projectFiles: string[], options?: DotNetPluginOptions): Promise<AnalysisResult>;
27
+ /**
28
+ * Read the cached analysis results without running the analyzer.
29
+ * This should be called by createDependencies, which always runs after createNodes.
30
+ * If the cache is empty, returns an empty result (this shouldn't happen in normal operation).
31
+ */
32
+ export declare function readCachedAnalysisResult(): AnalysisResult;
33
+ /**
34
+ * Clear the cache (useful for testing)
35
+ */
36
+ export declare function clearCache(): void;
37
+ export declare function isAnalysisErrorResult(result: AnalysisResult): result is AnalysisErrorResult;
38
+ export declare function isAnalysisSuccessResult(result: AnalysisResult): result is AnalysisSuccessResult;
39
+ //# sourceMappingURL=analyzer-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer-client.d.ts","sourceRoot":"","sources":["../../src/analyzer/analyzer-client.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAKpB,MAAM,WAAW,qBAAqB;IAEpC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAElD,gBAAgB,EAAE,MAAM,CACtB,MAAM,EACN;QAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,CAC7C,CAAC;CACH;AACD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,KAAK,CAAC;CACd;AACD,MAAM,MAAM,cAAc,GAAG,qBAAqB,GAAG,mBAAmB,CAAC;AA2CzE,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAgJD;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,OAAO,CAAC,cAAc,CAAC,CA2DzB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,CASzD;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAEjC;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,GACrB,MAAM,IAAI,mBAAmB,CAE/B;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,GACrB,MAAM,IAAI,qBAAqB,CAEjC"}
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeProjects = analyzeProjects;
4
+ exports.readCachedAnalysisResult = readCachedAnalysisResult;
5
+ exports.clearCache = clearCache;
6
+ exports.isAnalysisErrorResult = isAnalysisErrorResult;
7
+ exports.isAnalysisSuccessResult = isAnalysisSuccessResult;
8
+ const node_child_process_1 = require("node:child_process");
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = require("node:path");
11
+ const devkit_1 = require("@nx/devkit");
12
+ const workspace_context_1 = require("nx/src/utils/workspace-context");
13
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
14
+ const file_hasher_1 = require("nx/src/hasher/file-hasher");
15
+ const analyzerCaches = new Map();
16
+ function getCachePathForOptionsHash(optionsHash) {
17
+ return (0, node_path_1.join)(cache_directory_1.workspaceDataDirectory, `dotnet-${optionsHash}.hash`);
18
+ }
19
+ function readAnalyzerCache(optionsHash) {
20
+ if (analyzerCaches.has(optionsHash)) {
21
+ return analyzerCaches.get(optionsHash);
22
+ }
23
+ const cacheFilePath = getCachePathForOptionsHash(optionsHash);
24
+ try {
25
+ return JSON.parse((0, node_fs_1.readFileSync)(cacheFilePath, 'utf-8'));
26
+ }
27
+ catch {
28
+ return {};
29
+ }
30
+ }
31
+ function writeAnalyzerCache(optionsHash, cache) {
32
+ analyzerCaches.set(optionsHash, cache);
33
+ const cacheFilePath = getCachePathForOptionsHash(optionsHash);
34
+ const cacheDir = (0, node_path_1.dirname)(cacheFilePath);
35
+ if (!(0, node_fs_1.existsSync)(cacheDir)) {
36
+ (0, node_fs_1.mkdirSync)(cacheDir, { recursive: true });
37
+ }
38
+ try {
39
+ (0, devkit_1.writeJsonFile)(cacheFilePath, cache);
40
+ }
41
+ catch (error) {
42
+ devkit_1.logger.warn(`Failed to write .NET analyzer cache to ${cacheFilePath}: ${error.message}`);
43
+ }
44
+ }
45
+ let cache = null;
46
+ /**
47
+ * Get the path to the msbuild-analyzer executable
48
+ */
49
+ function getAnalyzerPath() {
50
+ const executableName = 'MsbuildAnalyzer.dll';
51
+ const possiblePaths = [
52
+ // When running from dist/packages/dotnet
53
+ (0, node_path_1.join)(__dirname, '..', 'lib', executableName),
54
+ // When running from packages/dotnet/src (development)
55
+ (0, node_path_1.join)(__dirname, 'lib', executableName),
56
+ ];
57
+ for (const path of possiblePaths) {
58
+ if ((0, node_fs_1.existsSync)(path)) {
59
+ return path;
60
+ }
61
+ }
62
+ throw new Error(`msbuild-analyzer not found at any expected location. Please build it first with: nx run dotnet:build-analyzer`);
63
+ }
64
+ /**
65
+ * Calculate a hash of all project files and Directory.Build.* files to determine if we need to re-analyze
66
+ */
67
+ async function calculateProjectFilesHash(projectFiles) {
68
+ const hash = await (0, workspace_context_1.hashWithWorkspaceContext)(devkit_1.workspaceRoot, projectFiles.concat('Directory.Build.*', '**/Directory.Build.*'));
69
+ return hash;
70
+ }
71
+ /**
72
+ * Run the msbuild-analyzer and return the results.
73
+ * Uses stdin for large file lists to avoid ARG_MAX issues.
74
+ */
75
+ function runAnalyzer(projectFiles, options) {
76
+ if (projectFiles.length === 0) {
77
+ return { nodesByFile: {}, referencesByRoot: {} };
78
+ }
79
+ const analyzerPath = getAnalyzerPath();
80
+ // Set environment variables for the analyzer process
81
+ const env = { ...process.env };
82
+ // TODO(@AgentEnder): Remove this if anyone reports issues with being unable
83
+ // to locate the .NET runtime, currently I'm not hitting the issue but when I was
84
+ // this solved it, and it took a deal of effort to track down so I'm leaving it here commented for now.
85
+ // In Nx 23, if no one has reported the issue, its probably safe to remove.
86
+ //
87
+ // On macOS/Linux, set library path to help find libhostfxr.dylib
88
+ // if (process.platform === 'darwin' || process.platform === 'linux') {
89
+ // const dotnetRoot = process.env.DOTNET_ROOT || '/usr/local/share/dotnet';
90
+ // const hostFxrPath = join(dotnetRoot, 'host', 'fxr');
91
+ // if (existsSync(hostFxrPath)) {
92
+ // const versions = readdirSync(hostFxrPath);
93
+ // if (versions.length > 0) {
94
+ // // Use the latest version
95
+ // const latestVersion = versions.sort().reverse()[0];
96
+ // const fxrDir = join(hostFxrPath, latestVersion);
97
+ // const envVar =
98
+ // process.platform === 'darwin'
99
+ // ? 'DYLD_FALLBACK_LIBRARY_PATH'
100
+ // : 'LD_LIBRARY_PATH';
101
+ // const currentValue = env[envVar];
102
+ // env[envVar] = currentValue ? `${fxrDir}:${currentValue}` : fxrDir;
103
+ // }
104
+ // }
105
+ // }
106
+ try {
107
+ let output;
108
+ // Prepare CLI arguments
109
+ const args = [analyzerPath, devkit_1.workspaceRoot];
110
+ // Add plugin options as JSON string if provided
111
+ if (options) {
112
+ args.push(JSON.stringify(options));
113
+ }
114
+ // Use stdin mode for large file lists to avoid ARG_MAX issues
115
+ const input = projectFiles.join('\n');
116
+ const result = (0, node_child_process_1.spawnSync)('dotnet', args, {
117
+ input,
118
+ encoding: 'utf-8',
119
+ maxBuffer: 10 * 1024 * 1024, // 10MB buffer
120
+ stdio: ['pipe', 'pipe', 'pipe'], // stdin, stdout, stderr
121
+ windowsHide: true,
122
+ env,
123
+ });
124
+ if (result.error) {
125
+ throw result.error;
126
+ }
127
+ if (result.status !== 0) {
128
+ throw new Error(`Analyzer exited with code ${result.status}: ${result.stderr}`);
129
+ }
130
+ // Output stderr (includes performance logs when NX_PERF_LOGGING=true)
131
+ if (result.stderr) {
132
+ console.error(result.stderr);
133
+ }
134
+ output = result.stdout;
135
+ return JSON.parse(output);
136
+ }
137
+ catch (error) {
138
+ const err = error;
139
+ if (err.stderr) {
140
+ devkit_1.logger.error(`msbuild-analyzer error: ${err.stderr}`);
141
+ }
142
+ throw new Error(`Failed to run msbuild-analyzer: ${err.message}${err.stderr ? `\n${err.stderr}` : ''}`);
143
+ }
144
+ }
145
+ /**
146
+ * Get project analysis results for the given project files.
147
+ * Results are cached based on the content hash of all project files.
148
+ * This should be called by createNodes to populate the cache.
149
+ */
150
+ async function analyzeProjects(projectFiles, options) {
151
+ const filesHash = await calculateProjectFilesHash(projectFiles);
152
+ // Return cached results if the hash matches
153
+ if (cache &&
154
+ cache.hash === filesHash &&
155
+ // NOTE: We don't read from the cache here if it's an error result,
156
+ // to allow retrying analysis in case of transient errors or errors fixed
157
+ // that may not be reflected in the hash (like setting an env var).
158
+ isAnalysisSuccessResult(cache.result)) {
159
+ return cache.result;
160
+ }
161
+ const optionsHash = (0, file_hasher_1.hashObject)(options);
162
+ const analyzerCache = readAnalyzerCache(optionsHash);
163
+ const cachedResult = analyzerCache[filesHash];
164
+ if (cachedResult) {
165
+ // Update cache
166
+ cache = {
167
+ hash: filesHash,
168
+ result: cachedResult,
169
+ };
170
+ return cachedResult;
171
+ }
172
+ // Run the analyzer
173
+ try {
174
+ const result = runAnalyzer(projectFiles, options);
175
+ // Update local cache
176
+ cache = {
177
+ hash: filesHash,
178
+ result,
179
+ };
180
+ // Update persistent cache
181
+ writeAnalyzerCache(optionsHash, {
182
+ ...analyzerCache,
183
+ [filesHash]: result,
184
+ });
185
+ return result;
186
+ }
187
+ catch (error) {
188
+ const err = error;
189
+ // We save the error result in the local cache to avoid getting
190
+ // a different error when reading the cached result to createDependencies.
191
+ // Instead, we'll find a cached error and know that it was printed earlier.
192
+ // We DO NOT save error results to the on-disk cache to allow retries without
193
+ // running `nx reset`
194
+ const errorResult = {
195
+ error: err,
196
+ };
197
+ cache = {
198
+ hash: filesHash,
199
+ result: errorResult,
200
+ };
201
+ return errorResult;
202
+ }
203
+ }
204
+ /**
205
+ * Read the cached analysis results without running the analyzer.
206
+ * This should be called by createDependencies, which always runs after createNodes.
207
+ * If the cache is empty, returns an empty result (this shouldn't happen in normal operation).
208
+ */
209
+ function readCachedAnalysisResult() {
210
+ if (cache) {
211
+ return cache.result;
212
+ }
213
+ // This shouldn't happen since createNodes always runs first
214
+ throw new Error('Analysis result cache is empty. Ensure that analyzeProjects() is called before readCachedAnalysisResult().');
215
+ }
216
+ /**
217
+ * Clear the cache (useful for testing)
218
+ */
219
+ function clearCache() {
220
+ cache = null;
221
+ }
222
+ function isAnalysisErrorResult(result) {
223
+ return 'error' in result;
224
+ }
225
+ function isAnalysisSuccessResult(result) {
226
+ return !('error' in result);
227
+ }
@@ -0,0 +1,7 @@
1
+ import { GeneratorCallback, Tree } from '@nx/devkit';
2
+ import { InitGeneratorSchema } from './schema';
3
+ export declare function initGenerator(tree: Tree, options: InitGeneratorSchema): Promise<GeneratorCallback>;
4
+ export declare function updateGitIgnore(tree: Tree): void;
5
+ export declare function updateNxJsonConfiguration(tree: Tree): void;
6
+ export default initGenerator;
7
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/generators/init/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,iBAAiB,EAIjB,IAAI,EAGL,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAG/C,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,8BA0B3E;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,QAqDzC;AAsBD,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,IAAI,QA0BnD;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.initGenerator = initGenerator;
4
+ exports.updateGitIgnore = updateGitIgnore;
5
+ exports.updateNxJsonConfiguration = updateNxJsonConfiguration;
6
+ const devkit_1 = require("@nx/devkit");
7
+ const ignore = require("ignore");
8
+ const versions_1 = require("../../utils/versions");
9
+ const has_dotnet_plugin_1 = require("../../utils/has-dotnet-plugin");
10
+ async function initGenerator(tree, options) {
11
+ const tasks = [];
12
+ if (!options.skipPackageJson && tree.exists('package.json')) {
13
+ tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
14
+ '@nx/dotnet': versions_1.nxVersion,
15
+ }, undefined, options.keepExistingVersions));
16
+ }
17
+ addPlugin(tree);
18
+ updateNxJsonConfiguration(tree);
19
+ updateGitIgnore(tree);
20
+ if (!options.skipFormat) {
21
+ await (0, devkit_1.formatFiles)(tree);
22
+ }
23
+ return (0, devkit_1.runTasksInSerial)(...tasks);
24
+ }
25
+ function updateGitIgnore(tree) {
26
+ const gitignorePath = '.gitignore';
27
+ if (tree.exists(gitignorePath)) {
28
+ let gitignore = tree.read(gitignorePath, 'utf-8');
29
+ const sectionHeader = '# .NET';
30
+ const potentialLinesToAdd = new Set(['**/bin/', '**/obj/', '/artifacts/']);
31
+ if (gitignore.includes(sectionHeader)) {
32
+ // Section already exists, do not modify
33
+ return;
34
+ }
35
+ // Line with issues -> files that would have been ignored.
36
+ const issues = new Map();
37
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
38
+ for (const line of potentialLinesToAdd) {
39
+ const ig = ignore();
40
+ ig.add(line);
41
+ if (ig.ignores(filePath)) {
42
+ if (!issues.has(line)) {
43
+ issues.set(line, []);
44
+ }
45
+ issues.get(line).push(filePath);
46
+ }
47
+ }
48
+ });
49
+ let hasIssues = issues.size > 0;
50
+ if (hasIssues) {
51
+ devkit_1.logger.warn(`The following .gitignore entries cannot be added because they would ignore existing files:`);
52
+ }
53
+ for (const [line, files] of issues) {
54
+ potentialLinesToAdd.delete(line);
55
+ devkit_1.logger.warn(`- "${line}" would ignore the following existing files:\n` +
56
+ files.map((f) => ` - ${f}`).join('\n'));
57
+ }
58
+ if (hasIssues) {
59
+ devkit_1.logger.warn(`Review the above patterns and manually update your .gitignore as necessary.`);
60
+ }
61
+ if (potentialLinesToAdd.size > 0) {
62
+ gitignore += `\n${sectionHeader}\n`;
63
+ for (const line of potentialLinesToAdd) {
64
+ gitignore += `${line}\n`;
65
+ }
66
+ tree.write(gitignorePath, gitignore);
67
+ }
68
+ }
69
+ }
70
+ function addPlugin(tree) {
71
+ const nxJson = (0, devkit_1.readNxJson)(tree);
72
+ if (!(0, has_dotnet_plugin_1.hasDotNetPlugin)(tree)) {
73
+ nxJson.plugins ??= [];
74
+ nxJson.plugins.push({
75
+ plugin: '@nx/dotnet',
76
+ options: {
77
+ buildTargetName: 'build',
78
+ testTargetName: 'test',
79
+ cleanTargetName: 'clean',
80
+ restoreTargetName: 'restore',
81
+ publishTargetName: 'publish',
82
+ packTargetName: 'pack',
83
+ },
84
+ });
85
+ (0, devkit_1.updateNxJson)(tree, nxJson);
86
+ }
87
+ }
88
+ function updateNxJsonConfiguration(tree) {
89
+ const nxJson = (0, devkit_1.readNxJson)(tree);
90
+ if (!nxJson.namedInputs) {
91
+ nxJson.namedInputs = {};
92
+ }
93
+ // Default inputs include all project files
94
+ const defaultFilesSet = nxJson.namedInputs.default ?? [];
95
+ nxJson.namedInputs.default = Array.from(new Set([...defaultFilesSet, '{projectRoot}/**/*']));
96
+ // Production inputs exclude test files and build outputs
97
+ const productionFileSet = nxJson.namedInputs.production ?? [];
98
+ nxJson.namedInputs.production = Array.from(new Set([
99
+ ...productionFileSet,
100
+ 'default',
101
+ '!{projectRoot}/**/*.Tests/**/*',
102
+ '!{projectRoot}/**/bin/**/*',
103
+ '!{projectRoot}/**/obj/**/*',
104
+ ]));
105
+ (0, devkit_1.updateNxJson)(tree, nxJson);
106
+ }
107
+ exports.default = initGenerator;
@@ -0,0 +1,6 @@
1
+ export interface InitGeneratorSchema {
2
+ skipFormat?: boolean;
3
+ skipPackageJson?: boolean;
4
+ keepExistingVersions?: boolean;
5
+ updatePackageScripts?: boolean;
6
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://json-schema.org/schema",
3
+ "$id": "NxDotNetInitSchema",
4
+ "title": ".NET Init Generator",
5
+ "description": "Initializes a .NET project in the current workspace.",
6
+ "type": "object",
7
+ "properties": {
8
+ "skipFormat": {
9
+ "description": "Skip formatting files.",
10
+ "type": "boolean",
11
+ "default": false,
12
+ "x-priority": "internal"
13
+ },
14
+ "skipPackageJson": {
15
+ "type": "boolean",
16
+ "default": false,
17
+ "description": "Do not add dependencies to `package.json`.",
18
+ "x-priority": "internal"
19
+ },
20
+ "keepExistingVersions": {
21
+ "type": "boolean",
22
+ "x-priority": "internal",
23
+ "description": "Keep existing dependencies versions",
24
+ "default": false
25
+ },
26
+ "updatePackageScripts": {
27
+ "type": "boolean",
28
+ "x-priority": "internal",
29
+ "description": "Update `package.json` scripts with inferred targets",
30
+ "default": false
31
+ }
32
+ },
33
+ "required": []
34
+ }
@@ -0,0 +1,3 @@
1
+ export * from './plugin';
2
+ export { DotNetPluginOptions } from './plugins/create-nodes';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AAEzB,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./plugin"), exports);
Binary file