@nx/dotnet 0.0.1 → 22.0.0-beta.8
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/README.md +117 -4
- package/README.md__tmpl__ +70 -0
- package/dist/analyzer/analyzer-client.d.ts +39 -0
- package/dist/analyzer/analyzer-client.d.ts.map +1 -0
- package/dist/analyzer/analyzer-client.js +227 -0
- package/dist/generators/init/init.d.ts +7 -0
- package/dist/generators/init/init.d.ts.map +1 -0
- package/dist/generators/init/init.js +107 -0
- package/dist/generators/init/schema.d.ts +6 -0
- package/dist/generators/init/schema.json +34 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/lib/Microsoft.Build.Locator.dll +0 -0
- package/dist/lib/MsbuildAnalyzer +0 -0
- package/dist/lib/MsbuildAnalyzer.deps.json +476 -0
- package/dist/lib/MsbuildAnalyzer.dll +0 -0
- package/dist/lib/MsbuildAnalyzer.dll.config +629 -0
- package/dist/lib/MsbuildAnalyzer.pdb +0 -0
- package/dist/lib/MsbuildAnalyzer.runtimeconfig.json +14 -0
- package/dist/plugin.d.ts +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +3 -2
- package/dist/plugins/create-dependencies.d.ts +4 -0
- package/dist/plugins/create-dependencies.d.ts.map +1 -0
- package/dist/plugins/create-dependencies.js +47 -0
- package/dist/{src/plugins/plugin.d.ts → plugins/create-nodes.d.ts} +2 -3
- package/dist/plugins/create-nodes.d.ts.map +1 -0
- package/dist/plugins/create-nodes.js +48 -0
- package/dist/plugins/plugin.d.ts +5 -0
- package/dist/plugins/plugin.d.ts.map +1 -0
- package/dist/plugins/plugin.js +14 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/has-dotnet-plugin.d.ts +3 -0
- package/dist/utils/has-dotnet-plugin.d.ts.map +1 -0
- package/dist/utils/has-dotnet-plugin.js +8 -0
- package/dist/utils/versions.d.ts +2 -0
- package/dist/utils/versions.d.ts.map +1 -0
- package/dist/utils/versions.js +5 -0
- package/generators.json +10 -0
- package/migrations.json +4 -0
- package/package.json +48 -59
- package/dist/package.json +0 -84
- package/dist/src/index.d.ts +0 -2
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -7
- package/dist/src/plugins/plugin.d.ts.map +0 -1
- package/dist/src/plugins/plugin.js +0 -130
- package/dist/src/utils/cache.d.ts.map +0 -1
- package/dist/src/utils/dependency-detection.d.ts +0 -5
- package/dist/src/utils/dependency-detection.d.ts.map +0 -1
- package/dist/src/utils/dependency-detection.js +0 -58
- package/dist/src/utils/dotnet-cli.d.ts +0 -9
- package/dist/src/utils/dotnet-cli.d.ts.map +0 -1
- package/dist/src/utils/dotnet-cli.js +0 -39
- package/dist/src/utils/dotnet-project-parser.d.ts +0 -13
- package/dist/src/utils/dotnet-project-parser.d.ts.map +0 -1
- package/dist/src/utils/dotnet-project-parser.js +0 -83
- package/dist/src/utils/logger.d.ts +0 -3
- package/dist/src/utils/logger.d.ts.map +0 -1
- package/dist/src/utils/logger.js +0 -24
- package/dist/src/utils/target-builder.d.ts +0 -12
- package/dist/src/utils/target-builder.d.ts.map +0 -1
- package/dist/src/utils/target-builder.js +0 -525
- package/plugin.ts +0 -5
- package/src/index.ts +0 -6
- package/src/plugins/plugin.ts +0 -230
- package/src/utils/cache.ts +0 -19
- package/src/utils/dependency-detection.ts +0 -84
- package/src/utils/dotnet-cli.ts +0 -52
- package/src/utils/dotnet-project-parser.ts +0 -105
- package/src/utils/logger.ts +0 -24
- package/src/utils/target-builder.ts +0 -657
- package/tsconfig.json +0 -16
- package/tsconfig.lib.json +0 -21
- /package/dist/{src/utils → utils}/cache.d.ts +0 -0
- /package/dist/{src/utils → utils}/cache.js +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,120 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
8
|
+
<div style="text-align: center;">
|
|
4
9
|
|
|
5
|
-
|
|
10
|
+
[](https://circleci.com/gh/nrwl/nx)
|
|
11
|
+
[]()
|
|
12
|
+
[](https://www.npmjs.com/package/nx)
|
|
13
|
+
[]()
|
|
14
|
+
[](http://commitizen.github.io/cz-cli/)
|
|
15
|
+
[](https://gitter.im/nrwl-nx/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
16
|
+
[](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,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
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
Binary file
|
|
Binary file
|