Compare commits
24 Commits
check-java
...
16.7.2
| Author | SHA1 | Date | |
|---|---|---|---|
| b024f44a1a | |||
| e4b64f5623 | |||
| 30fac6187f | |||
| f98d01eea8 | |||
| 7578e4ba4d | |||
| 83011f747c | |||
| 95099aec61 | |||
| 1857e8f6f1 | |||
| 894437bf61 | |||
| bcaecfd902 | |||
| bd80c805d5 | |||
| a459528819 | |||
| 76c96faa69 | |||
| f6a7f18143 | |||
| da3ca7608c | |||
| 3b1a1b3523 | |||
| 8b38708d6c | |||
| 28c3fa3f43 | |||
| 6a8a8a41ba | |||
| 0e6a353b33 | |||
| 1a4c483a34 | |||
| e2c0afeafb | |||
| a5d6e0a852 | |||
| 14d48c624c |
@@ -19,7 +19,10 @@ jest.debug.config.js
|
||||
/graph/client/src/assets/generated-task-graphs
|
||||
/nx-dev/nx-dev/public/documentation
|
||||
/nx-dev/nx-dev/public/images/open-graph
|
||||
|
||||
# Issues scraper creates these files, stored by github's cache
|
||||
/scripts/issues-scraper/cached
|
||||
|
||||
# Lerna creates this
|
||||
CHANGELOG.md
|
||||
|
||||
@@ -34,3 +37,6 @@ CHANGELOG.md
|
||||
.bashrc
|
||||
|
||||
*.node
|
||||
|
||||
# Fix for issue when working on the repo in a dev container
|
||||
.pnpm-store
|
||||
Generated
+10
@@ -1353,6 +1353,7 @@ dependencies = [
|
||||
"napi-build",
|
||||
"napi-derive",
|
||||
"once_cell",
|
||||
"os_type",
|
||||
"rayon",
|
||||
"regex",
|
||||
"swc_common",
|
||||
@@ -1378,6 +1379,15 @@ version = "1.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "os_type"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e24d44c0eea30167516ed8f6daca4b5e3eebcde1bde1e4e6e08b809fb02c7ba5"
|
||||
dependencies = [
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "overload"
|
||||
version = "0.1.1"
|
||||
|
||||
@@ -7,7 +7,6 @@ Context for [CreateNodesFunction](../../devkit/documents/CreateNodesFunction)
|
||||
### Properties
|
||||
|
||||
- [nxJsonConfiguration](../../devkit/documents/CreateNodesContext#nxjsonconfiguration)
|
||||
- [projectsConfigurations](../../devkit/documents/CreateNodesContext#projectsconfigurations)
|
||||
- [workspaceRoot](../../devkit/documents/CreateNodesContext#workspaceroot)
|
||||
|
||||
## Properties
|
||||
@@ -18,12 +17,6 @@ Context for [CreateNodesFunction](../../devkit/documents/CreateNodesFunction)
|
||||
|
||||
---
|
||||
|
||||
### projectsConfigurations
|
||||
|
||||
• `Readonly` **projectsConfigurations**: `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\>
|
||||
|
||||
---
|
||||
|
||||
### workspaceRoot
|
||||
|
||||
• `Readonly` **workspaceRoot**: `string`
|
||||
|
||||
@@ -138,12 +138,12 @@ It only uses language primitives and immutable objects
|
||||
- [offsetFromRoot](../../devkit/documents/offsetFromRoot)
|
||||
- [parseJson](../../devkit/documents/parseJson)
|
||||
- [parseTargetString](../../devkit/documents/parseTargetString)
|
||||
- [readAllWorkspaceConfiguration](../../devkit/documents/readAllWorkspaceConfiguration)
|
||||
- [readCachedProjectGraph](../../devkit/documents/readCachedProjectGraph)
|
||||
- [readJson](../../devkit/documents/readJson)
|
||||
- [readJsonFile](../../devkit/documents/readJsonFile)
|
||||
- [readNxJson](../../devkit/documents/readNxJson)
|
||||
- [readProjectConfiguration](../../devkit/documents/readProjectConfiguration)
|
||||
- [readProjectsConfigurationFromProjectGraph](../../devkit/documents/readProjectsConfigurationFromProjectGraph)
|
||||
- [readRootPackageJson](../../devkit/documents/readRootPackageJson)
|
||||
- [readTargetOptions](../../devkit/documents/readTargetOptions)
|
||||
- [readWorkspaceConfiguration](../../devkit/documents/readWorkspaceConfiguration)
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Class: Workspaces
|
||||
|
||||
**`Deprecated`**
|
||||
|
||||
This will be removed in v18. Use [readProjectsConfigurationFromProjectGraph](../../devkit/documents/readProjectsConfigurationFromProjectGraph) instead.
|
||||
|
||||
## Table of contents
|
||||
|
||||
### Constructors
|
||||
@@ -8,13 +12,10 @@
|
||||
|
||||
### Properties
|
||||
|
||||
- [cachedProjectsConfig](../../devkit/documents/Workspaces#cachedprojectsconfig)
|
||||
- [root](../../devkit/documents/Workspaces#root)
|
||||
|
||||
### Methods
|
||||
|
||||
- [mergeTargetDefaultsIntoProjectDescriptions](../../devkit/documents/Workspaces#mergetargetdefaultsintoprojectdescriptions)
|
||||
- [readProjectsConfigurations](../../devkit/documents/Workspaces#readprojectsconfigurations)
|
||||
- [readWorkspaceConfiguration](../../devkit/documents/Workspaces#readworkspaceconfiguration)
|
||||
|
||||
## Constructors
|
||||
@@ -31,67 +32,19 @@
|
||||
|
||||
## Properties
|
||||
|
||||
### cachedProjectsConfig
|
||||
|
||||
• `Private` **cachedProjectsConfig**: [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations)
|
||||
|
||||
---
|
||||
|
||||
### root
|
||||
|
||||
• `Private` **root**: `string`
|
||||
|
||||
## Methods
|
||||
|
||||
### mergeTargetDefaultsIntoProjectDescriptions
|
||||
### readWorkspaceConfiguration
|
||||
|
||||
▸ `Private` **mergeTargetDefaultsIntoProjectDescriptions**(`projects`, `nxJson`): `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\>
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :--------- | :----------------------------------------------------------------------------------------- |
|
||||
| `projects` | `Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\> |
|
||||
| `nxJson` | [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration)<`string`[] \| `"*"`\> |
|
||||
|
||||
#### Returns
|
||||
|
||||
`Record`<`string`, [`ProjectConfiguration`](../../devkit/documents/ProjectConfiguration)\>
|
||||
|
||||
---
|
||||
|
||||
### readProjectsConfigurations
|
||||
|
||||
▸ **readProjectsConfigurations**(`opts?`): [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations)
|
||||
▸ **readWorkspaceConfiguration**(): [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations) & [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration)<`string`[] \| `"*"`\>
|
||||
|
||||
**`Deprecated`**
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :-------------------------------------- | :-------- |
|
||||
| `opts?` | `Object` |
|
||||
| `opts._includeProjectsFromAngularJson?` | `boolean` |
|
||||
|
||||
#### Returns
|
||||
|
||||
[`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations)
|
||||
|
||||
---
|
||||
|
||||
### readWorkspaceConfiguration
|
||||
|
||||
▸ **readWorkspaceConfiguration**(`opts?`): [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations) & [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration)<`string`[] \| `"*"`\>
|
||||
|
||||
Deprecated. Use readProjectsConfigurations
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :-------------------------------------- | :-------- |
|
||||
| `opts?` | `Object` |
|
||||
| `opts._ignorePluginInference?` | `boolean` |
|
||||
| `opts._includeProjectsFromAngularJson?` | `boolean` |
|
||||
Use [readProjectsConfigurationFromProjectGraph](../../devkit/documents/readProjectsConfigurationFromProjectGraph) instead.
|
||||
|
||||
#### Returns
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Nx will compute it in the current process if:
|
||||
- It is running in the docker container.
|
||||
- The daemon process is disabled because of the previous error when starting the daemon.
|
||||
- `NX_DAEMON` is set to `false`.
|
||||
- `useDaemon` is set to false in `nx.json`
|
||||
- `useDaemonProcess` is set to false in the options of the tasks runner inside `nx.json`
|
||||
|
||||
`NX_DAEMON` env variable takes precedence:
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Function: readAllWorkspaceConfiguration
|
||||
|
||||
▸ **readAllWorkspaceConfiguration**(): [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations) & [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration)
|
||||
|
||||
**`Deprecated`**
|
||||
|
||||
Use readProjectsConfigurationFromProjectGraph(await createProjectGraphAsync())
|
||||
|
||||
#### Returns
|
||||
|
||||
[`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations) & [`NxJsonConfiguration`](../../devkit/documents/NxJsonConfiguration)
|
||||
@@ -0,0 +1,15 @@
|
||||
# Function: readProjectsConfigurationFromProjectGraph
|
||||
|
||||
▸ **readProjectsConfigurationFromProjectGraph**(`projectGraph`): [`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations)
|
||||
|
||||
Get the [ProjectsConfigurations](../../devkit/documents/ProjectsConfigurations) from the [ProjectGraph](../../devkit/documents/ProjectGraph)
|
||||
|
||||
#### Parameters
|
||||
|
||||
| Name | Type |
|
||||
| :------------- | :---------------------------------------------------- |
|
||||
| `projectGraph` | [`ProjectGraph`](../../devkit/documents/ProjectGraph) |
|
||||
|
||||
#### Returns
|
||||
|
||||
[`ProjectsConfigurations`](../../devkit/documents/ProjectsConfigurations)
|
||||
@@ -138,12 +138,12 @@ It only uses language primitives and immutable objects
|
||||
- [offsetFromRoot](../../devkit/documents/offsetFromRoot)
|
||||
- [parseJson](../../devkit/documents/parseJson)
|
||||
- [parseTargetString](../../devkit/documents/parseTargetString)
|
||||
- [readAllWorkspaceConfiguration](../../devkit/documents/readAllWorkspaceConfiguration)
|
||||
- [readCachedProjectGraph](../../devkit/documents/readCachedProjectGraph)
|
||||
- [readJson](../../devkit/documents/readJson)
|
||||
- [readJsonFile](../../devkit/documents/readJsonFile)
|
||||
- [readNxJson](../../devkit/documents/readNxJson)
|
||||
- [readProjectConfiguration](../../devkit/documents/readProjectConfiguration)
|
||||
- [readProjectsConfigurationFromProjectGraph](../../devkit/documents/readProjectsConfigurationFromProjectGraph)
|
||||
- [readRootPackageJson](../../devkit/documents/readRootPackageJson)
|
||||
- [readTargetOptions](../../devkit/documents/readTargetOptions)
|
||||
- [readWorkspaceConfiguration](../../devkit/documents/readWorkspaceConfiguration)
|
||||
|
||||
@@ -173,8 +173,10 @@ describe('Angular Module Federation', () => {
|
||||
|
||||
// ports
|
||||
const hostPort = 4500;
|
||||
const remote1Port = readProjectConfig(remote1).targets.serve.options.port;
|
||||
const remote2Port = readProjectConfig(remote2).targets.serve.options.port;
|
||||
const remote1Port = (await readProjectConfig(remote1)).targets.serve.options
|
||||
.port;
|
||||
const remote2Port = (await readProjectConfig(remote2)).targets.serve.options
|
||||
.port;
|
||||
|
||||
const process = await runCommandUntil(
|
||||
`serve-ssr ${host} --port=${hostPort}`,
|
||||
|
||||
@@ -268,7 +268,7 @@ describe('Angular Projects', () => {
|
||||
);
|
||||
|
||||
// update the angular.json
|
||||
updateProjectConfig(app1, (config) => {
|
||||
await updateProjectConfig(app1, (config) => {
|
||||
config.targets.build.executor = '@nx/angular:webpack-browser';
|
||||
config.targets.build.options = {
|
||||
...config.targets.build.options,
|
||||
@@ -276,7 +276,7 @@ describe('Angular Projects', () => {
|
||||
};
|
||||
return config;
|
||||
});
|
||||
updateProjectConfig(esbuildApp, (config) => {
|
||||
await updateProjectConfig(esbuildApp, (config) => {
|
||||
config.targets.build.executor = '@nx/angular:browser-esbuild';
|
||||
config.targets.build.options = {
|
||||
...config.targets.build.options,
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('Angular Cypress Component Tests', () => {
|
||||
|
||||
createBuildableLib(projectName, buildableLibName);
|
||||
|
||||
useWorkspaceAssetsInApp(appName);
|
||||
await useWorkspaceAssetsInApp(appName);
|
||||
});
|
||||
|
||||
afterAll(() => cleanupProject());
|
||||
@@ -265,7 +265,7 @@ export class AppModule {}
|
||||
);
|
||||
}
|
||||
|
||||
function useWorkspaceAssetsInApp(appName: string) {
|
||||
async function useWorkspaceAssetsInApp(appName: string) {
|
||||
// make sure assets from the workspace root work.
|
||||
createFile('libs/assets/data.json', JSON.stringify({ data: 'data' }));
|
||||
createFile(
|
||||
@@ -279,7 +279,7 @@ function useWorkspaceAssetsInApp(appName: string) {
|
||||
}
|
||||
`
|
||||
);
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets['build'].options.stylePreprocessorOptions = {
|
||||
includePaths: ['assets/styles'],
|
||||
};
|
||||
|
||||
@@ -360,7 +360,7 @@ describe('Tailwind support', () => {
|
||||
runCLI(
|
||||
`generate @nx/angular:app ${appWithTailwind} --add-tailwind --no-interactive`
|
||||
);
|
||||
updateProjectConfig(appWithTailwind, (config) => {
|
||||
await updateProjectConfig(appWithTailwind, (config) => {
|
||||
config.targets.build.executor = '@nx/angular:webpack-browser';
|
||||
config.targets.build.options = {
|
||||
...config.targets.build.options,
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
packageInstall,
|
||||
readFile,
|
||||
readJson,
|
||||
rmDist,
|
||||
runCLI,
|
||||
runCommand,
|
||||
runCommandUntil,
|
||||
@@ -27,7 +26,7 @@ describe('EsBuild Plugin', () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=esbuild`);
|
||||
updateFile(`libs/${myPkg}/src/index.ts`, `console.log('Hello');\n`);
|
||||
updateProjectConfig(myPkg, (json) => {
|
||||
await updateProjectConfig(myPkg, (json) => {
|
||||
json.targets.build.options.assets = [`libs/${myPkg}/assets/*`];
|
||||
return json;
|
||||
});
|
||||
@@ -179,12 +178,12 @@ describe('EsBuild Plugin', () => {
|
||||
expect(runCommand(`node dist/libs/${myPkg}`)).toMatch(/Hello/);
|
||||
}, 300_000);
|
||||
|
||||
it('should support additional entry points', () => {
|
||||
it('should support additional entry points', async () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=esbuild`);
|
||||
updateFile(`libs/${myPkg}/src/index.ts`, `console.log('main');\n`);
|
||||
updateFile(`libs/${myPkg}/src/extra.ts`, `console.log('extra');\n`);
|
||||
updateProjectConfig(myPkg, (json) => {
|
||||
await updateProjectConfig(myPkg, (json) => {
|
||||
json.targets.build.options.additionalEntryPoints = [
|
||||
`libs/${myPkg}/src/extra.ts`,
|
||||
];
|
||||
@@ -212,7 +211,7 @@ describe('EsBuild Plugin', () => {
|
||||
`libs/${myPkg}/esbuild.config.js`,
|
||||
`console.log('custom config loaded');\nmodule.exports = {};\n`
|
||||
);
|
||||
updateProjectConfig(myPkg, (json) => {
|
||||
await updateProjectConfig(myPkg, (json) => {
|
||||
delete json.targets.build.options.esbuildOptions;
|
||||
json.targets.build.options.esbuildConfig = `libs/${myPkg}/esbuild.config.js`;
|
||||
return json;
|
||||
|
||||
@@ -85,8 +85,8 @@ describe('expo', () => {
|
||||
it('should prebuild', async () => {
|
||||
// run prebuild command with git check disable
|
||||
// set a mock package name for ios and android in expo's app.json
|
||||
const workspace = readResolvedConfiguration();
|
||||
const root = workspace.projects[appName].root;
|
||||
const projects = await readResolvedConfiguration();
|
||||
const root = projects[appName].root;
|
||||
const appJsonPath = join(root, `app.json`);
|
||||
const appJson = await readJson(appJsonPath);
|
||||
if (appJson.expo.ios) {
|
||||
|
||||
+10
-10
@@ -16,7 +16,7 @@ describe('js:node error handling', () => {
|
||||
|
||||
afterEach(() => cleanupProject());
|
||||
|
||||
it('should log out the error', () => {
|
||||
it('should log out the error', async () => {
|
||||
const esbuildLib = uniq('esbuildlib');
|
||||
|
||||
runCLI(
|
||||
@@ -30,7 +30,7 @@ describe('js:node error handling', () => {
|
||||
`;
|
||||
});
|
||||
|
||||
updateProjectConfig(esbuildLib, (config) => {
|
||||
await updateProjectConfig(esbuildLib, (config) => {
|
||||
config.targets['run-node'] = {
|
||||
executor: '@nx/js:node',
|
||||
options: {
|
||||
@@ -48,7 +48,7 @@ describe('js:node error handling', () => {
|
||||
expect(output).toContain('This is an error');
|
||||
}, 240_000);
|
||||
|
||||
it('should execute library compiled with rollup', () => {
|
||||
it('should execute library compiled with rollup', async () => {
|
||||
const rollupLib = uniq('rolluplib');
|
||||
|
||||
runCLI(
|
||||
@@ -61,7 +61,7 @@ describe('js:node error handling', () => {
|
||||
`;
|
||||
});
|
||||
|
||||
updateProjectConfig(rollupLib, (config) => {
|
||||
await updateProjectConfig(rollupLib, (config) => {
|
||||
config.targets['run-node'] = {
|
||||
executor: '@nx/js:node',
|
||||
options: {
|
||||
@@ -76,7 +76,7 @@ describe('js:node error handling', () => {
|
||||
expect(output).toContain('Hello from my library!');
|
||||
}, 240_000);
|
||||
|
||||
it('should execute library compiled with tsc', () => {
|
||||
it('should execute library compiled with tsc', async () => {
|
||||
const tscLib = uniq('tsclib');
|
||||
|
||||
runCLI(`generate @nx/js:lib ${tscLib} --bundler=tsc --no-interactive`);
|
||||
@@ -87,7 +87,7 @@ describe('js:node error handling', () => {
|
||||
`;
|
||||
});
|
||||
|
||||
updateProjectConfig(tscLib, (config) => {
|
||||
await updateProjectConfig(tscLib, (config) => {
|
||||
config.targets['run-node'] = {
|
||||
executor: '@nx/js:node',
|
||||
options: {
|
||||
@@ -102,7 +102,7 @@ describe('js:node error handling', () => {
|
||||
expect(output).toContain('Hello from my tsc library!');
|
||||
}, 240_000);
|
||||
|
||||
it('should execute library compiled with swc', () => {
|
||||
it('should execute library compiled with swc', async () => {
|
||||
const swcLib = uniq('swclib');
|
||||
|
||||
runCLI(`generate @nx/js:lib ${swcLib} --bundler=swc --no-interactive`);
|
||||
@@ -113,7 +113,7 @@ describe('js:node error handling', () => {
|
||||
`;
|
||||
});
|
||||
|
||||
updateProjectConfig(swcLib, (config) => {
|
||||
await updateProjectConfig(swcLib, (config) => {
|
||||
config.targets['run-node'] = {
|
||||
executor: '@nx/js:node',
|
||||
options: {
|
||||
@@ -128,7 +128,7 @@ describe('js:node error handling', () => {
|
||||
expect(output).toContain('Hello from my swc library!');
|
||||
}, 240_000);
|
||||
|
||||
it('should execute webpack app', () => {
|
||||
it('should execute webpack app', async () => {
|
||||
const webpackProject = uniq('webpackproject');
|
||||
|
||||
runCLI(
|
||||
@@ -141,7 +141,7 @@ describe('js:node error handling', () => {
|
||||
`;
|
||||
});
|
||||
|
||||
updateProjectConfig(webpackProject, (config) => {
|
||||
await updateProjectConfig(webpackProject, (config) => {
|
||||
config.targets['run-node'] = {
|
||||
executor: '@nx/js:node',
|
||||
options: {
|
||||
|
||||
@@ -123,7 +123,7 @@ describe('bundling libs', () => {
|
||||
expect(output).toContain(rollupLib);
|
||||
}, 500_000);
|
||||
|
||||
it('should support tsc and swc for building libs', () => {
|
||||
it('should support tsc and swc for building libs', async () => {
|
||||
const tscLib = uniq('tsclib');
|
||||
const swcLib = uniq('swclib');
|
||||
const tscEsmLib = uniq('tscesmlib');
|
||||
@@ -154,7 +154,7 @@ describe('bundling libs', () => {
|
||||
);
|
||||
|
||||
// Add additional entry points for `exports` field
|
||||
updateProjectConfig(tscLib, (json) => {
|
||||
await updateProjectConfig(tscLib, (json) => {
|
||||
json.targets.build.options.additionalEntryPoints = [
|
||||
`libs/${tscLib}/src/foo/*.ts`,
|
||||
];
|
||||
@@ -162,7 +162,7 @@ describe('bundling libs', () => {
|
||||
});
|
||||
updateFile(`libs/${tscLib}/src/foo/bar.ts`, `export const bar = 'bar';`);
|
||||
updateFile(`libs/${tscLib}/src/foo/faz.ts`, `export const faz = 'faz';`);
|
||||
updateProjectConfig(swcLib, (json) => {
|
||||
await updateProjectConfig(swcLib, (json) => {
|
||||
json.targets.build.options.additionalEntryPoints = [
|
||||
`libs/${swcLib}/src/foo/*.ts`,
|
||||
];
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('Next.js Applications', () => {
|
||||
|
||||
// Additional assets that should be copied to dist
|
||||
const sharedLib = uniq('sharedLib');
|
||||
updateProjectConfig(appName, (json) => {
|
||||
await updateProjectConfig(appName, (json) => {
|
||||
json.targets.build.options.assets = [
|
||||
{
|
||||
glob: '**/*',
|
||||
@@ -367,7 +367,7 @@ describe('Next.js Applications', () => {
|
||||
checkFilesExist(`dist/apps/${appName}/next.config.js`);
|
||||
|
||||
// Make sure withNx works with run-commands.
|
||||
updateProjectConfig(appName, (json) => {
|
||||
await updateProjectConfig(appName, (json) => {
|
||||
json.targets.build = {
|
||||
command: 'npx next build',
|
||||
outputs: [`apps/${appName}/.next`],
|
||||
|
||||
@@ -151,7 +151,7 @@ describe('Node Applications + webpack', () => {
|
||||
runCLI(
|
||||
`generate @nx/node:app ${nodeApp2} --framework=none --no-interactive`
|
||||
);
|
||||
updateProjectConfig(nodeApp1, (config) => {
|
||||
await updateProjectConfig(nodeApp1, (config) => {
|
||||
config.targets.serve.options.waitUntilTargets = [`${nodeApp2}:build`];
|
||||
return config;
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('Node Applications + webpack', () => {
|
||||
const lib = uniq('nodelib');
|
||||
runCLI(`generate @nx/js:lib ${lib} --bundler=esbuild --no-interactive`);
|
||||
|
||||
updateProjectConfig(app, (config) => {
|
||||
await updateProjectConfig(app, (config) => {
|
||||
// Since we read from lib from dist, we should re-build it when lib changes.
|
||||
config.targets.build.options.buildLibsFromSource = false;
|
||||
config.targets.serve.options.runBuildTargetDependencies = true;
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('Node Applications', () => {
|
||||
const nodeapp = uniq('nodeapp');
|
||||
runCLI(`generate @nx/node:app ${nodeapp} --linter=eslint`);
|
||||
|
||||
updateProjectConfig(nodeapp, (config) => {
|
||||
await updateProjectConfig(nodeapp, (config) => {
|
||||
config.targets.build.options.outputFileName = 'index.js';
|
||||
return config;
|
||||
});
|
||||
@@ -94,7 +94,7 @@ describe('Node Applications', () => {
|
||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||
expect(lintResults).toContain('All files pass linting.');
|
||||
|
||||
updateProjectConfig(nodeapp, (config) => {
|
||||
await updateProjectConfig(nodeapp, (config) => {
|
||||
config.targets.build.options.additionalEntryPoints = [
|
||||
{
|
||||
entryName: 'additional-main',
|
||||
@@ -254,7 +254,7 @@ describe('Node Applications', () => {
|
||||
config.target = 'es2020';
|
||||
return config;
|
||||
});
|
||||
updateProjectConfig(esmapp, (config) => {
|
||||
await updateProjectConfig(esmapp, (config) => {
|
||||
config.targets.build.options.outputFileName = 'main.mjs';
|
||||
config.targets.build.options.assets = [];
|
||||
return config;
|
||||
@@ -436,7 +436,7 @@ ${jslib}();
|
||||
|
||||
packageInstall('@nestjs/swagger', undefined, '^6.0.0');
|
||||
|
||||
updateProjectConfig(nestapp, (config) => {
|
||||
await updateProjectConfig(nestapp, (config) => {
|
||||
config.targets.build.options.tsPlugins = ['@nestjs/swagger/plugin'];
|
||||
return config;
|
||||
});
|
||||
@@ -549,7 +549,7 @@ describe('nest libraries', function () {
|
||||
|
||||
packageInstall('@nestjs/swagger', undefined, '~6.3.0');
|
||||
|
||||
updateProjectConfig(nestlib, (config) => {
|
||||
await updateProjectConfig(nestlib, (config) => {
|
||||
config.targets.build.options.transformers = [
|
||||
{
|
||||
name: '@nestjs/swagger/plugin',
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
it('should stream output', async () => {
|
||||
const myapp = 'abcdefghijklmon';
|
||||
runCLI(`generate @nx/web:app ${myapp}`);
|
||||
updateProjectConfig(myapp, (c) => {
|
||||
await updateProjectConfig(myapp, (c) => {
|
||||
c.targets['inner'] = {
|
||||
command: 'echo inner',
|
||||
};
|
||||
@@ -122,7 +122,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
process.platform === 'win32'
|
||||
? `%SHARED_VAR% %ROOT_ONLY% %NESTED_ONLY%` // Windows
|
||||
: `$SHARED_VAR $ROOT_ONLY $NESTED_ONLY`;
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
config.targets.echoEnvVariables.options.command += ` ${command}`;
|
||||
return config;
|
||||
});
|
||||
@@ -135,7 +135,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
}, 120000);
|
||||
|
||||
it('should pass options', async () => {
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
config.targets.echo = {
|
||||
command: 'echo --var1={args.var1}',
|
||||
options: {
|
||||
@@ -151,7 +151,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
|
||||
it('should interpolate provided arguments', async () => {
|
||||
const echoTarget = uniq('echo');
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
config.targets[echoTarget] = {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
@@ -186,7 +186,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
}, 120000);
|
||||
|
||||
it('should fail when a process exits non-zero', async () => {
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
config.targets.error = {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
@@ -207,7 +207,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
});
|
||||
|
||||
it('run command should not break if output property is missing in options and arguments', async () => {
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
config.targets.lint.outputs = ['{options.outputFile}'];
|
||||
return config;
|
||||
});
|
||||
@@ -241,7 +241,7 @@ describe('Extra Nx Misc Tests', () => {
|
||||
: `mkdir -p ${folder}`,
|
||||
`echo dummy > ${folder}/dummy.txt`,
|
||||
];
|
||||
updateProjectConfig(mylib, (config) => {
|
||||
await updateProjectConfig(mylib, (config) => {
|
||||
delete config.targets.build.options.command;
|
||||
config.targets.build.options = {
|
||||
...config.targets.build.options,
|
||||
|
||||
@@ -113,7 +113,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib3, (config) => {
|
||||
await updateProjectConfig(lib3, (config) => {
|
||||
config.implicitDependencies = [`${lib1}-data-access`];
|
||||
return config;
|
||||
});
|
||||
@@ -172,13 +172,13 @@ describe('Workspace Tests', () => {
|
||||
expect(moveOutput).toContain(`CREATE ${rootClassPath}`);
|
||||
checkFilesExist(rootClassPath);
|
||||
|
||||
let workspace = await readResolvedConfiguration();
|
||||
expect(workspace.projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const newConfig = readProjectConfig(newName);
|
||||
let projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const newConfig = await readProjectConfig(newName);
|
||||
expect(newConfig).toMatchObject({
|
||||
tags: [],
|
||||
});
|
||||
const lib3Config = readProjectConfig(lib3);
|
||||
const lib3Config = await readProjectConfig(lib3);
|
||||
expect(lib3Config.implicitDependencies).toEqual([
|
||||
`shared-${lib1}-data-access`,
|
||||
]);
|
||||
@@ -194,9 +194,9 @@ describe('Workspace Tests', () => {
|
||||
]
|
||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
||||
|
||||
workspace = readResolvedConfiguration();
|
||||
expect(workspace.projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = readProjectConfig(newName);
|
||||
projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = await readProjectConfig(newName);
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||
@@ -251,7 +251,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib3, (config) => {
|
||||
await updateProjectConfig(lib3, (config) => {
|
||||
config.implicitDependencies = [`${lib1}-data-access`];
|
||||
return config;
|
||||
});
|
||||
@@ -321,13 +321,13 @@ describe('Workspace Tests', () => {
|
||||
]
|
||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
||||
|
||||
const workspace = await readResolvedConfiguration();
|
||||
expect(workspace.projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = readProjectConfig(newName);
|
||||
const projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = await readProjectConfig(newName);
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||
expect(project.tags).toEqual([]);
|
||||
const lib3Config = readProjectConfig(lib3);
|
||||
const lib3Config = await readProjectConfig(lib3);
|
||||
expect(lib3Config.implicitDependencies).toEqual([newName]);
|
||||
|
||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||
@@ -384,7 +384,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib3, (config) => {
|
||||
await updateProjectConfig(lib3, (config) => {
|
||||
config.implicitDependencies = [`${lib1}-data-access`];
|
||||
return config;
|
||||
});
|
||||
@@ -454,9 +454,9 @@ describe('Workspace Tests', () => {
|
||||
]
|
||||
).toEqual([`packages/shared/${lib1}/data-access/src/index.ts`]);
|
||||
|
||||
const workspace = await readResolvedConfiguration();
|
||||
expect(workspace.projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = readProjectConfig(newName);
|
||||
const projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = await readProjectConfig(newName);
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||
@@ -513,7 +513,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib3, (config) => {
|
||||
await updateProjectConfig(lib3, (config) => {
|
||||
config.implicitDependencies = [lib1];
|
||||
return config;
|
||||
});
|
||||
@@ -572,13 +572,13 @@ describe('Workspace Tests', () => {
|
||||
expect(moveOutput).toContain(`CREATE ${rootClassPath}`);
|
||||
checkFilesExist(rootClassPath);
|
||||
|
||||
let workspace = readResolvedConfiguration();
|
||||
expect(workspace.projects[lib1]).toBeUndefined();
|
||||
const newConfig = readProjectConfig(newName);
|
||||
let projects = await readResolvedConfiguration();
|
||||
expect(projects[lib1]).toBeUndefined();
|
||||
const newConfig = await readProjectConfig(newName);
|
||||
expect(newConfig).toMatchObject({
|
||||
tags: [],
|
||||
});
|
||||
const lib3Config = readProjectConfig(lib3);
|
||||
const lib3Config = await readProjectConfig(lib3);
|
||||
expect(lib3Config.implicitDependencies).toEqual([`${lib1}-data-access`]);
|
||||
|
||||
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
||||
@@ -590,9 +590,9 @@ describe('Workspace Tests', () => {
|
||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}/data-access`]
|
||||
).toEqual([`libs/${lib1}/data-access/src/index.ts`]);
|
||||
|
||||
workspace = readResolvedConfiguration();
|
||||
expect(workspace.projects[lib1]).toBeUndefined();
|
||||
const project = readProjectConfig(newName);
|
||||
projects = await readResolvedConfiguration();
|
||||
expect(projects[lib1]).toBeUndefined();
|
||||
const project = await readProjectConfig(newName);
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||
@@ -655,7 +655,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib3, (config) => {
|
||||
await updateProjectConfig(lib3, (config) => {
|
||||
config.implicitDependencies = [`${lib1}-data-access`];
|
||||
return config;
|
||||
});
|
||||
@@ -686,11 +686,11 @@ describe('Workspace Tests', () => {
|
||||
expect(moveOutput).toContain(`CREATE ${rootClassPath}`);
|
||||
checkFilesExist(rootClassPath);
|
||||
|
||||
const newConfig = readProjectConfig(newName);
|
||||
const newConfig = await readProjectConfig(newName);
|
||||
expect(newConfig).toMatchObject({
|
||||
tags: [],
|
||||
});
|
||||
const lib3Config = readProjectConfig(lib3);
|
||||
const lib3Config = await readProjectConfig(lib3);
|
||||
expect(lib3Config.implicitDependencies).toEqual([
|
||||
`shared-${lib1}-data-access`,
|
||||
]);
|
||||
@@ -704,9 +704,9 @@ describe('Workspace Tests', () => {
|
||||
rootTsConfig.compilerOptions.paths[`shared/${lib1}/data-access`]
|
||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
||||
|
||||
const projects = readResolvedConfiguration();
|
||||
expect(projects.projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = readProjectConfig(newName);
|
||||
const projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||
const project = await readProjectConfig(newName);
|
||||
expect(project).toBeTruthy();
|
||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||
@@ -741,7 +741,7 @@ describe('Workspace Tests', () => {
|
||||
*/
|
||||
|
||||
runCLI(`generate @nx/js:lib ${lib2} --unitTestRunner=jest`);
|
||||
updateProjectConfig(lib2, (config) => {
|
||||
await updateProjectConfig(lib2, (config) => {
|
||||
config.implicitDependencies = [lib1];
|
||||
return config;
|
||||
});
|
||||
@@ -775,12 +775,12 @@ describe('Workspace Tests', () => {
|
||||
expect(exists(tmpProjPath(`libs/${lib1}`))).toBeFalsy();
|
||||
|
||||
expect(removeOutputForced).not.toContain(`UPDATE nx.json`);
|
||||
const projectsConfigurations = readResolvedConfiguration();
|
||||
expect(projectsConfigurations.projects[`${lib1}`]).toBeUndefined();
|
||||
const lib2Config = readProjectConfig(lib2);
|
||||
const projects = await readResolvedConfiguration();
|
||||
expect(projects[`${lib1}`]).toBeUndefined();
|
||||
const lib2Config = await readProjectConfig(lib2);
|
||||
expect(lib2Config.implicitDependencies).toEqual([]);
|
||||
|
||||
expect(projectsConfigurations.projects[`${lib1}`]).toBeUndefined();
|
||||
expect(projects[`${lib1}`]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -214,11 +214,11 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
}
|
||||
}, 1000000);
|
||||
|
||||
it('should detect changes to projects based on tags changes', () => {
|
||||
it('should detect changes to projects based on tags changes', async () => {
|
||||
// TODO: investigate why affected gives different results on windows
|
||||
if (isNotWindows()) {
|
||||
generateAll();
|
||||
updateProjectConfig(myapp, (config) => ({
|
||||
await updateProjectConfig(myapp, (config) => ({
|
||||
...config,
|
||||
tags: ['tag'],
|
||||
}));
|
||||
@@ -229,9 +229,9 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('should affect all projects by removing projects', () => {
|
||||
it('should affect all projects by removing projects', async () => {
|
||||
generateAll();
|
||||
const root = readResolvedConfiguration().projects[mylib].root;
|
||||
const root = (await readResolvedConfiguration())[mylib].root;
|
||||
removeFile(root);
|
||||
const output = runCLI('print-affected --select projects');
|
||||
expect(output).toContain(myapp);
|
||||
@@ -239,9 +239,9 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
expect(output).not.toContain(mylib);
|
||||
});
|
||||
|
||||
it('should detect changes to implicitly dependant projects', () => {
|
||||
it('should detect changes to implicitly dependant projects', async () => {
|
||||
generateAll();
|
||||
updateProjectConfig(myapp, (config) => ({
|
||||
await updateProjectConfig(myapp, (config) => ({
|
||||
...config,
|
||||
implicitDependencies: ['*', `!${myapp2}`],
|
||||
}));
|
||||
@@ -256,7 +256,7 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
expect(output).toContain(mylib);
|
||||
|
||||
// Clear implicit deps to not interfere with other tests.
|
||||
updateProjectConfig(myapp, (config) => ({
|
||||
await updateProjectConfig(myapp, (config) => ({
|
||||
...config,
|
||||
implicitDependencies: [],
|
||||
}));
|
||||
|
||||
@@ -156,7 +156,7 @@ describe('cache', () => {
|
||||
it('should support using globs as outputs', async () => {
|
||||
const mylib = uniq('mylib');
|
||||
runCLI(`generate @nx/js:library ${mylib}`);
|
||||
updateProjectConfig(mylib, (c) => {
|
||||
await updateProjectConfig(mylib, (c) => {
|
||||
c.targets.build = {
|
||||
executor: 'nx:run-commands',
|
||||
outputs: ['{workspaceRoot}/dist/!(.next)/**/!(z|x).(txt|md)'],
|
||||
|
||||
@@ -16,7 +16,7 @@ describe('Invoke Runner', () => {
|
||||
it('should invoke runner imperatively ', async () => {
|
||||
const mylib = uniq('mylib');
|
||||
runCLI(`generate @nx/js:lib ${mylib}`);
|
||||
updateProjectConfig(mylib, (c) => {
|
||||
await updateProjectConfig(mylib, (c) => {
|
||||
c.targets['prebuild'] = {
|
||||
command: 'echo prebuild',
|
||||
};
|
||||
|
||||
+18
-18
@@ -28,9 +28,9 @@ describe('Nx Running Tests', () => {
|
||||
describe('running targets', () => {
|
||||
describe('(forwarding params)', () => {
|
||||
let proj = uniq('proj');
|
||||
beforeAll(() => {
|
||||
beforeAll(async () => {
|
||||
runCLI(`generate @nx/js:lib ${proj}`);
|
||||
updateProjectConfig(proj, (c) => {
|
||||
await updateProjectConfig(proj, (c) => {
|
||||
c.targets['echo'] = {
|
||||
command: 'echo ECHO:',
|
||||
};
|
||||
@@ -57,7 +57,7 @@ describe('Nx Running Tests', () => {
|
||||
it('should execute long running tasks', async () => {
|
||||
const myapp = uniq('myapp');
|
||||
runCLI(`generate @nx/web:app ${myapp}`);
|
||||
updateProjectConfig(myapp, (c) => {
|
||||
await updateProjectConfig(myapp, (c) => {
|
||||
c.targets['counter'] = {
|
||||
executor: '@nx/workspace:counter',
|
||||
options: {
|
||||
@@ -79,8 +79,8 @@ describe('Nx Running Tests', () => {
|
||||
runCLI(`generate @nx/node:lib ${mylib}`);
|
||||
|
||||
// Used to restore targets to lib after test
|
||||
const original = readProjectConfig(mylib);
|
||||
updateProjectConfig(mylib, (j) => {
|
||||
const original = await readProjectConfig(mylib);
|
||||
await updateProjectConfig(mylib, (j) => {
|
||||
delete j.targets;
|
||||
return j;
|
||||
});
|
||||
@@ -113,7 +113,7 @@ describe('Nx Running Tests', () => {
|
||||
`Cannot find configuration for task ${mylib}:echo:fail`
|
||||
);
|
||||
|
||||
updateProjectConfig(mylib, (c) => original);
|
||||
await updateProjectConfig(mylib, (c) => original);
|
||||
}, 1000000);
|
||||
|
||||
describe('tokens support', () => {
|
||||
@@ -125,7 +125,7 @@ describe('Nx Running Tests', () => {
|
||||
});
|
||||
|
||||
it('should support using {projectRoot} in options blocks in project.json', async () => {
|
||||
updateProjectConfig(app, (c) => {
|
||||
await updateProjectConfig(app, (c) => {
|
||||
c.targets['echo'] = {
|
||||
command: `node -e 'console.log("{projectRoot}")'`,
|
||||
};
|
||||
@@ -137,7 +137,7 @@ describe('Nx Running Tests', () => {
|
||||
});
|
||||
|
||||
it('should support using {projectName} in options blocks in project.json', async () => {
|
||||
updateProjectConfig(app, (c) => {
|
||||
await updateProjectConfig(app, (c) => {
|
||||
c.targets['echo'] = {
|
||||
command: `node -e 'console.log("{projectName}")'`,
|
||||
};
|
||||
@@ -157,7 +157,7 @@ describe('Nx Running Tests', () => {
|
||||
};
|
||||
return json;
|
||||
});
|
||||
updateProjectConfig(app, (c) => {
|
||||
await updateProjectConfig(app, (c) => {
|
||||
c.targets['echo'] = {};
|
||||
return c;
|
||||
});
|
||||
@@ -174,7 +174,7 @@ describe('Nx Running Tests', () => {
|
||||
};
|
||||
return json;
|
||||
});
|
||||
updateProjectConfig(app, (c) => {
|
||||
await updateProjectConfig(app, (c) => {
|
||||
c.targets['echo'] = {};
|
||||
return c;
|
||||
});
|
||||
@@ -190,13 +190,13 @@ describe('Nx Running Tests', () => {
|
||||
const myapp2 = uniq('b');
|
||||
runCLI(`generate @nx/web:app ${myapp1}`);
|
||||
runCLI(`generate @nx/web:app ${myapp2}`);
|
||||
updateProjectConfig(myapp1, (c) => {
|
||||
await updateProjectConfig(myapp1, (c) => {
|
||||
c.targets['error'] = {
|
||||
command: 'echo boom1 && exit 1',
|
||||
};
|
||||
return c;
|
||||
});
|
||||
updateProjectConfig(myapp2, (c) => {
|
||||
await updateProjectConfig(myapp2, (c) => {
|
||||
c.targets['error'] = {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
@@ -431,9 +431,9 @@ describe('Nx Running Tests', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should be able to include deps using dependsOn', () => {
|
||||
const originalWorkspace = readProjectConfig(myapp);
|
||||
updateProjectConfig(myapp, (config) => {
|
||||
it('should be able to include deps using dependsOn', async () => {
|
||||
const originalWorkspace = await readProjectConfig(myapp);
|
||||
await updateProjectConfig(myapp, (config) => {
|
||||
config.targets.prep = {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
@@ -453,12 +453,12 @@ describe('Nx Running Tests', () => {
|
||||
expect(output).toContain(mylib2);
|
||||
expect(output).toContain('PREP');
|
||||
|
||||
updateProjectConfig(myapp, () => originalWorkspace);
|
||||
await updateProjectConfig(myapp, () => originalWorkspace);
|
||||
}, 10000);
|
||||
|
||||
it('should be able to include deps using target defaults defined at the root', () => {
|
||||
it('should be able to include deps using target defaults defined at the root', async () => {
|
||||
const nxJson = readJson('nx.json');
|
||||
updateProjectConfig(myapp, (config) => {
|
||||
await updateProjectConfig(myapp, (config) => {
|
||||
config.targets.prep = {
|
||||
command: 'echo PREP > one.txt',
|
||||
};
|
||||
|
||||
@@ -381,14 +381,14 @@ describe('Nx Plugin', () => {
|
||||
});
|
||||
|
||||
describe('--directory', () => {
|
||||
it('should create a plugin in the specified directory', () => {
|
||||
it('should create a plugin in the specified directory', async () => {
|
||||
const plugin = uniq('plugin');
|
||||
runCLI(
|
||||
`generate @nx/plugin:plugin ${plugin} --linter=eslint --directory subdir --e2eTestRunner=jest`
|
||||
);
|
||||
checkFilesExist(`libs/subdir/${plugin}/package.json`);
|
||||
const pluginProject = readProjectConfig(`subdir-${plugin}`);
|
||||
const pluginE2EProject = readProjectConfig(`subdir-${plugin}-e2e`);
|
||||
const pluginProject = await readProjectConfig(`subdir-${plugin}`);
|
||||
const pluginE2EProject = await readProjectConfig(`subdir-${plugin}-e2e`);
|
||||
expect(pluginProject.targets).toBeDefined();
|
||||
expect(pluginE2EProject).toBeTruthy();
|
||||
}, 90000);
|
||||
@@ -399,7 +399,7 @@ describe('Nx Plugin', () => {
|
||||
runCLI(
|
||||
`generate @nx/plugin:plugin ${plugin} --linter=eslint --tags=e2etag,e2ePackage `
|
||||
);
|
||||
const pluginProject = readProjectConfig(plugin);
|
||||
const pluginProject = await readProjectConfig(plugin);
|
||||
expect(pluginProject.tags).toEqual(['e2etag', 'e2ePackage']);
|
||||
}, 90000);
|
||||
});
|
||||
|
||||
@@ -114,8 +114,8 @@ describe('React Module Federation', () => {
|
||||
// }
|
||||
}, 500_000);
|
||||
|
||||
function readPort(appName: string): number {
|
||||
const config = readProjectConfig(appName);
|
||||
async function readPort(appName: string): Promise<number> {
|
||||
const config = await readProjectConfig(appName);
|
||||
return config.targets.serve.options.port;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ describe('Build React libraries and apps', () => {
|
||||
|
||||
let proj: string;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
app = uniq('app');
|
||||
parentLib = uniq('parentlib');
|
||||
childLib = uniq('childlib');
|
||||
@@ -99,7 +99,7 @@ describe('Build React libraries and apps', () => {
|
||||
);
|
||||
|
||||
// Add assets to child lib
|
||||
updateProjectConfig(childLib, (json) => {
|
||||
await updateProjectConfig(childLib, (json) => {
|
||||
json.targets.build.options.assets = [`libs/${childLib}/src/assets`];
|
||||
return json;
|
||||
});
|
||||
|
||||
@@ -234,14 +234,14 @@ describe('React Applications', () => {
|
||||
${'scss'}
|
||||
${'less'}
|
||||
${'styl'}
|
||||
`('should support global and css modules', ({ style }) => {
|
||||
`('should support global and css modules', async ({ style }) => {
|
||||
const appName = uniq('app');
|
||||
runCLI(
|
||||
`generate @nx/react:app ${appName} --style=${style} --bundler=webpack --no-interactive`
|
||||
);
|
||||
|
||||
// make sure stylePreprocessorOptions works
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets.build.options.stylePreprocessorOptions = {
|
||||
includePaths: ['libs/shared/lib'],
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('React Cypress Component Tests', () => {
|
||||
const usedInAppLibName = uniq('cy-react-lib');
|
||||
const buildableLibName = uniq('cy-react-buildable-lib');
|
||||
|
||||
beforeAll(() => {
|
||||
beforeAll(async () => {
|
||||
projectName = newProject({ name: uniq('cy-react') });
|
||||
ensureCypressInstallation();
|
||||
|
||||
@@ -131,7 +131,7 @@ export default Input;
|
||||
`
|
||||
);
|
||||
createFile('libs/assets/data.json', JSON.stringify({ data: 'data' }));
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets['build'].options.assets.push({
|
||||
glob: '**/*',
|
||||
input: 'libs/assets',
|
||||
@@ -228,7 +228,7 @@ ${content}`;
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
it('should work with async webpack config', () => {
|
||||
it('should work with async webpack config', async () => {
|
||||
// TODO: (caleb) for whatever reason the MF webpack config + CT is running, but cypress is not starting up?
|
||||
// are they overriding some option on top of each other causing cypress to not see it's running?
|
||||
createFile(
|
||||
@@ -252,7 +252,7 @@ ${content}`;
|
||||
);
|
||||
`
|
||||
);
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets[
|
||||
'build'
|
||||
].options.webpackConfig = `apps/${appName}/webpack.config.js`;
|
||||
|
||||
@@ -37,7 +37,7 @@ describe('Rollup Plugin', () => {
|
||||
let output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateProjectConfig(myPkg, (config) => {
|
||||
await updateProjectConfig(myPkg, (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
@@ -51,7 +51,7 @@ describe('Rollup Plugin', () => {
|
||||
output = runCommand(`node dist/libs/${myPkg}/index.cjs.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateProjectConfig(myPkg, (config) => {
|
||||
await updateProjectConfig(myPkg, (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
@@ -66,13 +66,13 @@ describe('Rollup Plugin', () => {
|
||||
expect(output).toMatch(/Hello/);
|
||||
}, 500000);
|
||||
|
||||
it('should support additional entry-points', () => {
|
||||
it('should support additional entry-points', async () => {
|
||||
const myPkg = uniq('my-pkg');
|
||||
runCLI(`generate @nx/js:lib ${myPkg} --bundler=none`);
|
||||
runCLI(
|
||||
`generate @nx/rollup:configuration ${myPkg} --target=node --tsConfig=libs/${myPkg}/tsconfig.lib.json --main=libs/${myPkg}/src/index.ts --compiler=tsc`
|
||||
);
|
||||
updateProjectConfig(myPkg, (config) => {
|
||||
await updateProjectConfig(myPkg, (config) => {
|
||||
config.targets.build.options.format = ['cjs', 'esm'];
|
||||
config.targets.build.options.generateExportsField = true;
|
||||
config.targets.build.options.additionalEntryPoints = [
|
||||
|
||||
@@ -14,10 +14,11 @@ import { TargetConfiguration } from '@nx/devkit';
|
||||
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import * as isCI from 'is-ci';
|
||||
import { Workspaces } from '../../packages/nx/src/config/workspaces';
|
||||
import { fileExists, readJson, updateFile } from './file-utils';
|
||||
import { logError, stripConsoleColors } from './log-utils';
|
||||
import { existsSync } from 'fs-extra';
|
||||
import { retrieveProjectConfigurationsSync } from '../../packages/nx/src/project-graph/utils/retrieve-workspace-files';
|
||||
import { readNxJson } from '../../packages/nx/src/config/nx-json';
|
||||
|
||||
export interface RunCmdOpts {
|
||||
silenceError?: boolean;
|
||||
@@ -36,11 +37,14 @@ export interface RunCmdOpts {
|
||||
*/
|
||||
export function setMaxWorkers() {
|
||||
if (isCI) {
|
||||
const ws = new Workspaces(tmpProjPath());
|
||||
const projectsConfigurations = ws.readProjectsConfigurations();
|
||||
const root = tmpProjPath();
|
||||
const projects = retrieveProjectConfigurationsSync(
|
||||
root,
|
||||
readNxJson(root)
|
||||
).projectNodes;
|
||||
|
||||
Object.keys(projectsConfigurations.projects).forEach((appName) => {
|
||||
let project = projectsConfigurations.projects[appName];
|
||||
Object.keys(projects).forEach((appName) => {
|
||||
let project = projects[appName];
|
||||
const { build } = project.targets as {
|
||||
[targetName: string]: TargetConfiguration<any>;
|
||||
};
|
||||
|
||||
@@ -1,27 +1,34 @@
|
||||
import { ProjectConfiguration, Workspaces } from '@nx/devkit';
|
||||
import { ProjectConfiguration } from '@nx/devkit';
|
||||
import { join } from 'path';
|
||||
import { tmpProjPath } from './create-project-utils';
|
||||
import { readJson, updateFile } from './file-utils';
|
||||
import { retrieveProjectConfigurations } from '../../packages/nx/src/project-graph/utils/retrieve-workspace-files';
|
||||
import { readNxJson } from '../../packages/nx/src/config/nx-json';
|
||||
|
||||
export function updateProjectConfig(
|
||||
export async function updateProjectConfig(
|
||||
projectName: string,
|
||||
callback: (c: ProjectConfiguration) => ProjectConfiguration
|
||||
) {
|
||||
const workspace = readResolvedConfiguration();
|
||||
const root = workspace.projects[projectName].root;
|
||||
const projects = await readResolvedConfiguration();
|
||||
const root = projects[projectName].root;
|
||||
const path = join(root, 'project.json');
|
||||
const current = readJson(path);
|
||||
updateFile(path, JSON.stringify(callback(current), null, 2));
|
||||
}
|
||||
|
||||
export function readResolvedConfiguration() {
|
||||
export async function readResolvedConfiguration(): Promise<
|
||||
Record<string, ProjectConfiguration>
|
||||
> {
|
||||
process.env.NX_PROJECT_GLOB_CACHE = 'false';
|
||||
const ws = new Workspaces(tmpProjPath());
|
||||
return ws.readProjectsConfigurations();
|
||||
const root = tmpProjPath();
|
||||
return (await retrieveProjectConfigurations(root, readNxJson(root)))
|
||||
.projectNodes;
|
||||
}
|
||||
|
||||
export function readProjectConfig(projectName: string): ProjectConfiguration {
|
||||
const root = readResolvedConfiguration().projects[projectName].root;
|
||||
export async function readProjectConfig(
|
||||
projectName: string
|
||||
): Promise<ProjectConfiguration> {
|
||||
const root = (await readResolvedConfiguration())[projectName].root;
|
||||
const path = join(root, 'project.json');
|
||||
return readJson(path);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ describe('Vite Plugin', () => {
|
||||
});
|
||||
|
||||
describe('set up new React app with --bundler=vite option', () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
proj = newProject();
|
||||
runCLI(`generate @nx/react:app ${myApp} --bundler=vite`);
|
||||
createFile(`apps/${myApp}/public/hello.md`, `# Hello World`);
|
||||
@@ -99,7 +99,7 @@ describe('Vite Plugin', () => {
|
||||
`
|
||||
);
|
||||
|
||||
updateProjectConfig(myApp, (config) => {
|
||||
await updateProjectConfig(myApp, (config) => {
|
||||
config.targets.build.options.fileReplacements = [
|
||||
{
|
||||
replace: `apps/${myApp}/src/environments/environment.ts`,
|
||||
@@ -380,7 +380,7 @@ export default App;
|
||||
}, 100_000);
|
||||
|
||||
// TODO: This takes forever and times out everything - find out why
|
||||
xit('should not delete the project directory when coverage is enabled', () => {
|
||||
xit('should not delete the project directory when coverage is enabled', async () => {
|
||||
// when coverage is enabled in the vite.config.ts but reportsDirectory is removed
|
||||
// from the @nx/vite:test executor options, vite will delete the project root directory
|
||||
runCLI(`generate @nx/react:lib ${lib} --unitTestRunner=vitest`);
|
||||
@@ -416,7 +416,7 @@ export default defineConfig({
|
||||
});
|
||||
`;
|
||||
});
|
||||
updateProjectConfig(lib, (config) => {
|
||||
await updateProjectConfig(lib, (config) => {
|
||||
delete config.targets.test.options.reportsDirectory;
|
||||
return config;
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@ describe('file-server', () => {
|
||||
const port = 4301;
|
||||
|
||||
runCLI(`generate @nx/web:app ${appName} --no-interactive`);
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets['serve'].executor = '@nx/web:file-server';
|
||||
return config;
|
||||
});
|
||||
|
||||
@@ -262,7 +262,7 @@ describe('Web Components Applications', () => {
|
||||
`generate @nx/web:app ${appName} --bundler=webpack --no-interactive`
|
||||
);
|
||||
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
config.targets.build.options.webpackConfig = `apps/${appName}/webpack.config.js`;
|
||||
return config;
|
||||
});
|
||||
@@ -411,7 +411,7 @@ describe('CLI - Environment Variables', () => {
|
||||
});
|
||||
|
||||
describe('Build Options', () => {
|
||||
it('should inject/bundle external scripts and styles', () => {
|
||||
it('should inject/bundle external scripts and styles', async () => {
|
||||
newProject();
|
||||
|
||||
const appName = uniq('app');
|
||||
@@ -444,7 +444,7 @@ describe('Build Options', () => {
|
||||
const barScriptsBundleName = 'bar-scripts';
|
||||
const barStylesBundleName = 'bar-styles';
|
||||
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
const buildOptions = config.targets.build.options;
|
||||
|
||||
buildOptions.scripts = [
|
||||
@@ -492,7 +492,7 @@ describe('Build Options', () => {
|
||||
});
|
||||
|
||||
describe('index.html interpolation', () => {
|
||||
test('should interpolate environment variables', () => {
|
||||
test('should interpolate environment variables', async () => {
|
||||
const appName = uniq('app');
|
||||
|
||||
runCLI(
|
||||
@@ -530,7 +530,7 @@ describe('index.html interpolation', () => {
|
||||
updateFile(envFilePath, envFileContents);
|
||||
updateFile(indexPath, indexContent);
|
||||
|
||||
updateProjectConfig(appName, (config) => {
|
||||
await updateProjectConfig(appName, (config) => {
|
||||
const buildOptions = config.targets.build.options;
|
||||
buildOptions.deployUrl = 'baz';
|
||||
return config;
|
||||
|
||||
@@ -45,7 +45,7 @@ module.exports = composePlugins(withNx(), (config) => {
|
||||
expect(output).not.toMatch(/Conflicting/);
|
||||
expect(output).not.toMatch(/process.env.NODE_ENV/);
|
||||
|
||||
updateProjectConfig(myPkg, (config) => {
|
||||
await updateProjectConfig(myPkg, (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
@@ -59,7 +59,7 @@ module.exports = composePlugins(withNx(), (config) => {
|
||||
output = runCommand(`node dist/libs/${myPkg}/main.js`);
|
||||
expect(output).toMatch(/Hello/);
|
||||
|
||||
updateProjectConfig(myPkg, (config) => {
|
||||
await updateProjectConfig(myPkg, (config) => {
|
||||
delete config.targets.build;
|
||||
return config;
|
||||
});
|
||||
|
||||
@@ -450,11 +450,13 @@ describe('create-nx-workspace parent folder', () => {
|
||||
describe('create-nx-workspace yarn berry', () => {
|
||||
const tmpDir = `${e2eCwd}/${uniq('yarn-berry')}`;
|
||||
let wsName: string;
|
||||
let yarnVersion: string;
|
||||
|
||||
beforeAll(() => {
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
runCommand('corepack prepare yarn@stable --activate', { cwd: tmpDir });
|
||||
runCommand('yarn set version stable', { cwd: tmpDir });
|
||||
runCommand('corepack prepare yarn@3.6.1 --activate', { cwd: tmpDir });
|
||||
runCommand('yarn set version 3.6.1', { cwd: tmpDir });
|
||||
yarnVersion = runCommand('yarn --version', { cwd: tmpDir }).trim();
|
||||
// previous command creates a package.json file which we don't want
|
||||
rmSync(`${tmpDir}/package.json`);
|
||||
process.env.YARN_ENABLE_IMMUTABLE_INSTALLS = 'false';
|
||||
@@ -477,7 +479,7 @@ describe('create-nx-workspace yarn berry', () => {
|
||||
).toMatchInlineSnapshot(`
|
||||
"nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.6.1.cjs
|
||||
yarnPath: .yarn/releases/yarn-${yarnVersion}.cjs
|
||||
"
|
||||
`);
|
||||
});
|
||||
@@ -497,7 +499,7 @@ describe('create-nx-workspace yarn berry', () => {
|
||||
).toMatchInlineSnapshot(`
|
||||
"nodeLinker: node-modules
|
||||
|
||||
yarnPath: .yarn/releases/yarn-3.6.1.cjs
|
||||
yarnPath: .yarn/releases/yarn-${yarnVersion}.cjs
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"packages": ["build/packages/*", "build/packages/nx/native-packages/*"],
|
||||
"version": "16.7.0",
|
||||
"version": "16.7.2",
|
||||
"granularPathspec": false,
|
||||
"command": {
|
||||
"publish": {
|
||||
|
||||
@@ -38,17 +38,15 @@ export function getPackageManagerCommand(
|
||||
exec: string;
|
||||
preInstall?: string;
|
||||
} {
|
||||
const [pmMajor, pmMinor] =
|
||||
getPackageManagerVersion(packageManager).split('.');
|
||||
const pmVersion = getPackageManagerVersion(packageManager);
|
||||
const [pmMajor, pmMinor] = pmVersion.split('.');
|
||||
|
||||
switch (packageManager) {
|
||||
case 'yarn':
|
||||
const useBerry = +pmMajor >= 2;
|
||||
const installCommand = 'yarn install --silent';
|
||||
return {
|
||||
preInstall: useBerry
|
||||
? 'yarn set version stable'
|
||||
: 'yarn set version classic',
|
||||
preInstall: `yarn set version ${pmVersion}`,
|
||||
install: useBerry
|
||||
? installCommand
|
||||
: `${installCommand} --ignore-scripts`,
|
||||
|
||||
@@ -47,10 +47,7 @@ export type {
|
||||
*/
|
||||
export { Workspaces } from 'nx/src/config/workspaces';
|
||||
|
||||
export {
|
||||
readAllWorkspaceConfiguration,
|
||||
workspaceLayout,
|
||||
} from 'nx/src/config/configuration';
|
||||
export { workspaceLayout } from 'nx/src/config/configuration';
|
||||
|
||||
export type {
|
||||
NxPlugin,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type { Target } from 'nx/src/command-line/run/run';
|
||||
import type { ProjectGraph } from 'nx/src/config/project-graph';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { splitTarget } from 'nx/src/utils/split-target';
|
||||
import { requireNx } from '../../nx';
|
||||
|
||||
const { readCachedProjectGraph } = requireNx();
|
||||
let { readCachedProjectGraph, splitTarget } = requireNx();
|
||||
|
||||
// TODO: Remove this in Nx 18 when Nx 16.7.0 is no longer supported
|
||||
splitTarget = splitTarget ?? require('nx/src/utils/split-target').splitTarget;
|
||||
|
||||
/**
|
||||
* @deprecated(v17) A project graph should be passed to parseTargetString for best accuracy.
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import type { Target } from 'nx/src/command-line/run/run';
|
||||
import type { ExecutorContext } from 'nx/src/config/misc-interfaces';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { combineOptionsForExecutor } from 'nx/src/utils/params';
|
||||
import { requireNx } from '../../nx';
|
||||
import { relative } from 'path';
|
||||
|
||||
const { Workspaces, getExecutorInformation, calculateDefaultProjectName } =
|
||||
requireNx();
|
||||
let {
|
||||
Workspaces,
|
||||
getExecutorInformation,
|
||||
calculateDefaultProjectName,
|
||||
combineOptionsForExecutor,
|
||||
} = requireNx();
|
||||
|
||||
// TODO: Remove this in Nx 18 when Nx 16.7.0 is no longer supported
|
||||
combineOptionsForExecutor =
|
||||
combineOptionsForExecutor ??
|
||||
require('nx/src/utils/params').combineOptionsForExecutor;
|
||||
|
||||
/**
|
||||
* Reads and combines options for a given target.
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import type { Tree } from 'nx/src/generators/tree';
|
||||
import * as path from 'path';
|
||||
import type * as Prettier from 'prettier';
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { sortObjectByKeys } from 'nx/src/utils/object-sort';
|
||||
import { requireNx } from '../../nx';
|
||||
|
||||
const { updateJson, readJson } = requireNx();
|
||||
let { updateJson, readJson, sortObjectByKeys } = requireNx();
|
||||
|
||||
// TODO: Remove this in Nx 18 when Nx 16.7.0 is no longer supported
|
||||
sortObjectByKeys =
|
||||
sortObjectByKeys ?? require('nx/src/utils/object-sort').sortObjectByKeys;
|
||||
|
||||
/**
|
||||
* Formats all the created or updated files using Prettier
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import type { Observable } from 'rxjs';
|
||||
import type { Executor, ExecutorContext } from 'nx/src/config/misc-interfaces';
|
||||
import type { ProjectsConfigurations } from 'nx/src/devkit-exports';
|
||||
|
||||
import { requireNx } from '../../nx';
|
||||
|
||||
const { Workspaces, readNxJsonFromDisk } = requireNx();
|
||||
const {
|
||||
Workspaces,
|
||||
readNxJsonFromDisk,
|
||||
retrieveProjectConfigurationsWithAngularProjects,
|
||||
} = requireNx();
|
||||
|
||||
/**
|
||||
* Convert an Nx Executor into an Angular Devkit Builder
|
||||
@@ -17,11 +23,22 @@ export function convertNxExecutor(executor: Executor) {
|
||||
? readNxJsonFromDisk(builderContext.workspaceRoot)
|
||||
: // TODO(v18): remove readNxJson. This is to be backwards compatible with Nx 16.5 and below.
|
||||
(workspaces as any).readNxJson();
|
||||
const projectsConfigurations = workspaces.readProjectsConfigurations({
|
||||
_includeProjectsFromAngularJson: true,
|
||||
});
|
||||
|
||||
const promise = async () => {
|
||||
const projectsConfigurations: ProjectsConfigurations =
|
||||
retrieveProjectConfigurationsWithAngularProjects
|
||||
? {
|
||||
version: 2,
|
||||
projects: await retrieveProjectConfigurationsWithAngularProjects(
|
||||
builderContext.workspaceRoot,
|
||||
nxJsonConfiguration
|
||||
).then((p) => p.projectNodes),
|
||||
}
|
||||
: // TODO(v18): remove retrieveProjectConfigurations. This is to be backwards compatible with Nx 16.5 and below.
|
||||
(workspaces as any).readProjectsConfigurations({
|
||||
_includeProjectsFromAngularJson: true,
|
||||
});
|
||||
|
||||
const context: ExecutorContext = {
|
||||
root: builderContext.workspaceRoot,
|
||||
projectName: builderContext.target.project,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
// eslint-disable-next-line @nx/enforce-module-boundaries
|
||||
import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace';
|
||||
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
|
||||
import { getWorkspaceLayout } from './get-workspace-layout';
|
||||
|
||||
describe('getWorkspaceLayout', () => {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { stripIndent } from 'nx/src/utils/logger';
|
||||
import type {
|
||||
FileChange,
|
||||
Tree,
|
||||
@@ -13,7 +11,10 @@ import { join, relative } from 'path';
|
||||
import type { Mode } from 'fs';
|
||||
import { requireNx } from '../../nx';
|
||||
|
||||
const { logger } = requireNx();
|
||||
let { logger, stripIndent } = requireNx();
|
||||
|
||||
// TODO: Remove this in Nx 18 when Nx 16.7.0 is no longer supported
|
||||
stripIndent = stripIndent ?? require('nx/src/utils/logger').stripIndent;
|
||||
|
||||
class RunCallbackTask {
|
||||
constructor(private callback: GeneratorCallback) {}
|
||||
|
||||
@@ -3,11 +3,16 @@ import { WorkspaceLibrarySecondaryEntryPoint } from './models';
|
||||
import { dirname, join, relative } from 'path';
|
||||
import { existsSync, lstatSync, readdirSync } from 'fs';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { PackageJson, readModulePackageJson } from 'nx/src/utils/package-json';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { requireNx } from '../../../nx';
|
||||
|
||||
const { readJsonFile, joinPathFragments, workspaceRoot } = requireNx();
|
||||
let { readJsonFile, joinPathFragments, workspaceRoot, readModulePackageJson } =
|
||||
requireNx();
|
||||
|
||||
// TODO: Remove this in Nx 18 when Nx 16.7.0 is no longer supported
|
||||
readModulePackageJson =
|
||||
readModulePackageJson ??
|
||||
require('nx/src/utils/package-json').readModulePackageJson;
|
||||
|
||||
export function collectWorkspaceLibrarySecondaryEntryPoints(
|
||||
library: WorkspaceLibrary,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
DepConstraint,
|
||||
findConstraintsFor,
|
||||
findTransitiveExternalDependencies,
|
||||
getSourceFilePath,
|
||||
hasBannedDependencies,
|
||||
hasBannedImport,
|
||||
hasNoneOfTheseTags,
|
||||
@@ -558,3 +559,19 @@ describe('hasNoneOfTheseTags', () => {
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('getSourceFilePath', () => {
|
||||
it.each([
|
||||
['/root/libs/dev-kit/package.json', '/root'],
|
||||
['/root/libs/dev-kit/package.json', 'C:\\root'],
|
||||
['C:\\root\\libs\\dev-kit\\package.json', '/root'],
|
||||
['C:\\root\\libs\\dev-kit\\package.json', 'C:\\root'],
|
||||
])(
|
||||
'should return "libs/dev-kit/package.json" when sourceFileName is "%s" and projectPath is "%s"',
|
||||
(sourceFileName, projectPath) => {
|
||||
expect(getSourceFilePath(sourceFileName, projectPath)).toBe(
|
||||
'libs/dev-kit/package.json'
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
@@ -222,8 +222,9 @@ export function onlyLoadChildren(
|
||||
}
|
||||
|
||||
export function getSourceFilePath(sourceFileName: string, projectPath: string) {
|
||||
const relativePath = sourceFileName.slice(projectPath.length + 1);
|
||||
return normalizePath(relativePath);
|
||||
const normalizedProjectPath = normalizePath(projectPath);
|
||||
const normalizedSourceFileName = normalizePath(sourceFileName);
|
||||
return normalizedSourceFileName.slice(normalizedProjectPath.length + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -743,4 +743,4 @@ function determineEntryFields(
|
||||
}
|
||||
|
||||
export default libraryGenerator;
|
||||
export const librarySchematic = convertNxGenerator(libraryGeneratorInternal);
|
||||
export const librarySchematic = convertNxGenerator(libraryGenerator);
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import 'dotenv/config';
|
||||
import {
|
||||
detectPackageManager,
|
||||
ExecutorContext,
|
||||
getPackageManagerVersion,
|
||||
logger,
|
||||
readJsonFile,
|
||||
workspaceRoot,
|
||||
writeJsonFile,
|
||||
} from '@nx/devkit';
|
||||
import { createLockFile, createPackageJson, getLockFileName } from '@nx/js';
|
||||
import { join } from 'path';
|
||||
import { join, resolve as pathResolve } from 'path';
|
||||
import { copySync, existsSync, mkdir, writeFileSync } from 'fs-extra';
|
||||
import { gte } from 'semver';
|
||||
import { directoryExists } from '@nx/workspace/src/utilities/fileutils';
|
||||
@@ -19,9 +17,11 @@ import { updatePackageJson } from './lib/update-package-json';
|
||||
import { createNextConfigFile } from './lib/create-next-config-file';
|
||||
import { checkPublicDirectory } from './lib/check-project';
|
||||
import { NextBuildBuilderOptions } from '../../utils/types';
|
||||
import { execSync, ExecSyncOptions } from 'child_process';
|
||||
import { ChildProcess, fork } from 'child_process';
|
||||
import { createCliOptions } from '../../utils/create-cli-options';
|
||||
|
||||
let childProcess: ChildProcess;
|
||||
|
||||
export default async function buildExecutor(
|
||||
options: NextBuildBuilderOptions,
|
||||
context: ExecutorContext
|
||||
@@ -49,32 +49,16 @@ export default async function buildExecutor(
|
||||
process.env['__NEXT_REACT_ROOT'] ||= 'true';
|
||||
}
|
||||
|
||||
const { experimentalAppOnly, profile, debug, outputPath } = options;
|
||||
|
||||
// Set output path here since it can also be set via CLI
|
||||
// We can retrieve it inside plugins/with-nx
|
||||
process.env.NX_NEXT_OUTPUT_PATH ??= outputPath;
|
||||
|
||||
const args = createCliOptions({ experimentalAppOnly, profile, debug });
|
||||
const isYarnBerry =
|
||||
detectPackageManager() === 'yarn' &&
|
||||
gte(getPackageManagerVersion('yarn', workspaceRoot), '2.0.0');
|
||||
const buildCommand = isYarnBerry
|
||||
? `yarn next build ${projectRoot}`
|
||||
: 'npx next build';
|
||||
|
||||
const command = `${buildCommand} ${args.join(' ')}`;
|
||||
const execSyncOptions: ExecSyncOptions = {
|
||||
stdio: 'inherit',
|
||||
encoding: 'utf-8',
|
||||
cwd: projectRoot,
|
||||
};
|
||||
try {
|
||||
execSync(command, execSyncOptions);
|
||||
await runCliBuild(workspaceRoot, projectRoot, options);
|
||||
} catch (error) {
|
||||
logger.error(`Error occurred while trying to run the ${command}`);
|
||||
logger.error(`Error occurred while trying to run the build command`);
|
||||
logger.error(error);
|
||||
return { success: false };
|
||||
} finally {
|
||||
if (childProcess) {
|
||||
childProcess.kill();
|
||||
}
|
||||
}
|
||||
|
||||
if (!directoryExists(options.outputPath)) {
|
||||
@@ -116,3 +100,44 @@ export default async function buildExecutor(
|
||||
}
|
||||
return { success: true };
|
||||
}
|
||||
|
||||
function runCliBuild(
|
||||
workspaceRoot: string,
|
||||
projectRoot: string,
|
||||
options: NextBuildBuilderOptions
|
||||
) {
|
||||
const { experimentalAppOnly, profile, debug, outputPath } = options;
|
||||
|
||||
// Set output path here since it can also be set via CLI
|
||||
// We can retrieve it inside plugins/with-nx
|
||||
process.env.NX_NEXT_OUTPUT_PATH ??= outputPath;
|
||||
|
||||
const args = createCliOptions({ experimentalAppOnly, profile, debug });
|
||||
return new Promise((resolve, reject) => {
|
||||
childProcess = fork(
|
||||
require.resolve('next/dist/bin/next'),
|
||||
['build', ...args],
|
||||
{
|
||||
cwd: pathResolve(workspaceRoot, projectRoot),
|
||||
stdio: 'inherit',
|
||||
env: process.env,
|
||||
}
|
||||
);
|
||||
|
||||
// Ensure the child process is killed when the parent exits
|
||||
process.on('exit', () => childProcess.kill());
|
||||
process.on('SIGTERM', () => childProcess.kill());
|
||||
|
||||
childProcess.on('error', (err) => {
|
||||
reject(err);
|
||||
});
|
||||
|
||||
childProcess.on('exit', (code) => {
|
||||
if (code === 0) {
|
||||
resolve(code);
|
||||
} else {
|
||||
reject(code);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ ignore = '0.4'
|
||||
ignore-files = "1.3.0"
|
||||
itertools = "0.10.5"
|
||||
once_cell = "1.18.0"
|
||||
os_type = "2.6.0"
|
||||
napi = { version = '2.12.6', default-features = false, features = ['anyhow', 'napi4', 'tokio_rt'] }
|
||||
napi-derive = '2.9.3'
|
||||
regex = "1.9.1"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as memfs from 'memfs';
|
||||
|
||||
import '../src/utils/testing/mock-fs';
|
||||
import { getNxPackageJsonWorkspacesPlugin } from './package-json-workspaces';
|
||||
import { createNodeFromPackageJson } from './package-json-workspaces';
|
||||
|
||||
describe('nx package.json workspaces plugin', () => {
|
||||
it('should build projects from package.json files', () => {
|
||||
@@ -15,21 +15,29 @@ describe('nx package.json workspaces plugin', () => {
|
||||
name: 'lib-a',
|
||||
scripts: { test: 'jest' },
|
||||
}),
|
||||
'packages/lib-b/package.json': JSON.stringify({
|
||||
name: 'lib-b',
|
||||
scripts: {
|
||||
build: 'tsc',
|
||||
test: 'jest',
|
||||
nonNxOperation: 'rm -rf .',
|
||||
},
|
||||
nx: {
|
||||
implicitDependencies: ['lib-a'],
|
||||
includedScripts: ['build', 'test'],
|
||||
targets: {
|
||||
build: {
|
||||
outputs: ['{projectRoot}/dist'],
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
|
||||
const plugin = getNxPackageJsonWorkspacesPlugin('/root');
|
||||
|
||||
// Targets from package.json files are handled outside of `createNodes`,
|
||||
// because they are recognized even if the package.json file is not included
|
||||
// in the package manager workspaces configuration.
|
||||
//
|
||||
// If any project has a package.json file in its root directory, those scripts
|
||||
// are targets regardless of this plugin. As such, all we have to do here is identify
|
||||
// that the package.json represents an Nx project, and `normalizeProjectNodes`
|
||||
// will handle the rest.
|
||||
expect(plugin.createNodes[1]('package.json', null)).toMatchInlineSnapshot(`
|
||||
expect(createNodeFromPackageJson('package.json', '/root'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"root": {
|
||||
@@ -37,11 +45,19 @@ describe('nx package.json workspaces plugin', () => {
|
||||
"projectType": "library",
|
||||
"root": ".",
|
||||
"sourceRoot": ".",
|
||||
"targets": {
|
||||
"echo": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "echo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(plugin.createNodes[1]('packages/lib-a/package.json', null))
|
||||
expect(createNodeFromPackageJson('packages/lib-a/package.json', '/root'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
@@ -50,6 +66,51 @@ describe('nx package.json workspaces plugin', () => {
|
||||
"projectType": "library",
|
||||
"root": "packages/lib-a",
|
||||
"sourceRoot": "packages/lib-a",
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
expect(createNodeFromPackageJson('packages/lib-b/package.json', '/root'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"lib-b": {
|
||||
"implicitDependencies": [
|
||||
"lib-a",
|
||||
],
|
||||
"includedScripts": [
|
||||
"build",
|
||||
"test",
|
||||
],
|
||||
"name": "lib-b",
|
||||
"projectType": "library",
|
||||
"root": "packages/lib-b",
|
||||
"sourceRoot": "packages/lib-b",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "build",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
},
|
||||
"test": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ import { combineGlobPatterns } from '../src/utils/globs';
|
||||
import { NX_PREFIX } from '../src/utils/logger';
|
||||
import { NxPluginV2 } from '../src/utils/nx-plugin';
|
||||
import { output } from '../src/utils/output';
|
||||
import { PackageJson } from '../src/utils/package-json';
|
||||
import {
|
||||
PackageJson,
|
||||
readTargetsFromPackageJson,
|
||||
} from '../src/utils/package-json';
|
||||
import { joinPathFragments } from '../src/utils/path';
|
||||
|
||||
export function getNxPackageJsonWorkspacesPlugin(root: string): NxPluginV2 {
|
||||
@@ -20,24 +23,26 @@ export function getNxPackageJsonWorkspacesPlugin(root: string): NxPluginV2 {
|
||||
combineGlobPatterns(
|
||||
getGlobPatternsFromPackageManagerWorkspaces(root, readJson)
|
||||
),
|
||||
(pkgJsonPath) => {
|
||||
const json: PackageJson = readJson(pkgJsonPath);
|
||||
return {
|
||||
projects: {
|
||||
[json.name]: buildProjectConfigurationFromPackageJson(
|
||||
json,
|
||||
pkgJsonPath,
|
||||
readNxJson(root)
|
||||
),
|
||||
},
|
||||
};
|
||||
},
|
||||
(p) => createNodeFromPackageJson(p, root),
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
export function createNodeFromPackageJson(pkgJsonPath: string, root: string) {
|
||||
const json: PackageJson = readJsonFile(join(root, pkgJsonPath));
|
||||
return {
|
||||
projects: {
|
||||
[json.name]: buildProjectConfigurationFromPackageJson(
|
||||
json,
|
||||
pkgJsonPath,
|
||||
readNxJson(root)
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildProjectConfigurationFromPackageJson(
|
||||
packageJson: { name: string },
|
||||
packageJson: PackageJson,
|
||||
path: string,
|
||||
nxJson: NxJsonConfiguration
|
||||
): ProjectConfiguration & { name: string } {
|
||||
@@ -69,6 +74,8 @@ export function buildProjectConfigurationFromPackageJson(
|
||||
sourceRoot: directory,
|
||||
name,
|
||||
projectType,
|
||||
...packageJson.nx,
|
||||
targets: readTargetsFromPackageJson(packageJson),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,13 @@
|
||||
export const projectFilePatterns = ['package.json'];
|
||||
import type { NxPluginV2 } from '../src/utils/nx-plugin';
|
||||
import { workspaceRoot } from '../src/utils/workspace-root';
|
||||
import { createNodeFromPackageJson } from './package-json-workspaces';
|
||||
|
||||
const plugin: NxPluginV2 = {
|
||||
name: 'nx-all-package-jsons-plugin',
|
||||
createNodes: [
|
||||
'*/**/package.json',
|
||||
(f) => createNodeFromPackageJson(f, workspaceRoot),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = plugin;
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import * as memfs from 'memfs';
|
||||
|
||||
import '../src/utils/testing/mock-fs';
|
||||
import { getNxProjectJsonPlugin } from './project-json';
|
||||
|
||||
import { PackageJson } from '../src/utils/package-json';
|
||||
|
||||
import {
|
||||
getNxProjectJsonPlugin,
|
||||
mergeNpmScriptsWithTargets,
|
||||
} from './project-json';
|
||||
|
||||
describe('nx project.json plugin', () => {
|
||||
it('should build projects from project.json', () => {
|
||||
@@ -14,8 +20,17 @@ describe('nx project.json plugin', () => {
|
||||
'packages/lib-a/project.json': JSON.stringify({
|
||||
name: 'lib-a',
|
||||
targets: {
|
||||
executor: 'nx:run-commands',
|
||||
options: {},
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
}),
|
||||
'packages/lib-a/package.json': JSON.stringify({
|
||||
name: 'lib-a',
|
||||
scripts: {
|
||||
build: 'should not see me',
|
||||
test: 'jest',
|
||||
},
|
||||
}),
|
||||
},
|
||||
@@ -44,12 +59,172 @@ describe('nx project.json plugin', () => {
|
||||
"name": "lib-a",
|
||||
"root": "packages/lib-a",
|
||||
"targets": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {},
|
||||
"build": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {},
|
||||
},
|
||||
"test": {
|
||||
"executor": "nx:run-script",
|
||||
"options": {
|
||||
"script": "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
describe('mergeNpmScriptsWithTargets', () => {
|
||||
const packageJson: PackageJson = {
|
||||
name: 'my-app',
|
||||
version: '0.0.0',
|
||||
scripts: {
|
||||
build: 'echo 1',
|
||||
},
|
||||
};
|
||||
|
||||
const packageJsonBuildTarget = {
|
||||
executor: 'nx:run-script',
|
||||
options: {
|
||||
script: 'build',
|
||||
},
|
||||
};
|
||||
|
||||
it('should prefer project.json targets', () => {
|
||||
const projectJsonTargets = {
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
command: 'echo 2',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeNpmScriptsWithTargets(
|
||||
packageJson,
|
||||
projectJsonTargets
|
||||
);
|
||||
expect(result).toEqual(projectJsonTargets);
|
||||
});
|
||||
|
||||
it('should provide targets from project.json and package.json', () => {
|
||||
const projectJsonTargets = {
|
||||
clean: {
|
||||
executor: 'nx:run-commands',
|
||||
options: {
|
||||
command: 'echo 2',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const result = mergeNpmScriptsWithTargets(
|
||||
packageJson,
|
||||
projectJsonTargets
|
||||
);
|
||||
expect(result).toEqual({
|
||||
...projectJsonTargets,
|
||||
build: packageJsonBuildTarget,
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain extended options from nx property in package.json', () => {
|
||||
const result = mergeNpmScriptsWithTargets(
|
||||
{
|
||||
name: 'my-other-app',
|
||||
version: '',
|
||||
scripts: {
|
||||
build: 'echo 1',
|
||||
},
|
||||
nx: {
|
||||
targets: {
|
||||
build: {
|
||||
outputs: ['custom'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
null
|
||||
);
|
||||
expect(result).toEqual({
|
||||
build: { ...packageJsonBuildTarget, outputs: ['custom'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should work when project.json targets is null', () => {
|
||||
const result = mergeNpmScriptsWithTargets(packageJson, null);
|
||||
|
||||
expect(result).toEqual({
|
||||
build: {
|
||||
executor: 'nx:run-script',
|
||||
options: {
|
||||
script: 'build',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should work when project root is ''", () => {
|
||||
const result = mergeNpmScriptsWithTargets(
|
||||
{
|
||||
name: 'my-app',
|
||||
version: '',
|
||||
scripts: {
|
||||
test: 'echo testing',
|
||||
},
|
||||
},
|
||||
{
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command: 'echo hi' },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command: 'echo hi' },
|
||||
},
|
||||
test: {
|
||||
executor: 'nx:run-script',
|
||||
options: { script: 'test' },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore scripts that are not in includedScripts', () => {
|
||||
const result = mergeNpmScriptsWithTargets(
|
||||
{
|
||||
name: 'included-scripts-test',
|
||||
version: '',
|
||||
scripts: {
|
||||
test: 'echo testing',
|
||||
fail: 'exit 1',
|
||||
},
|
||||
nx: {
|
||||
includedScripts: ['test'],
|
||||
},
|
||||
},
|
||||
{
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command: 'echo hi' },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
build: {
|
||||
executor: 'nx:run-commands',
|
||||
options: { command: 'echo hi' },
|
||||
},
|
||||
test: {
|
||||
executor: 'nx:run-script',
|
||||
options: { script: 'test' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import { dirname, join } from 'node:path';
|
||||
import { existsSync } from 'node:fs';
|
||||
|
||||
import { ProjectConfiguration } from '../src/config/workspace-json-project-json';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
} from '../src/config/workspace-json-project-json';
|
||||
import { toProjectName } from '../src/config/workspaces';
|
||||
import { readJsonFile } from '../src/utils/fileutils';
|
||||
import { NxPluginV2 } from '../src/utils/nx-plugin';
|
||||
import {
|
||||
PackageJson,
|
||||
readTargetsFromPackageJson,
|
||||
} from '../src/utils/package-json';
|
||||
|
||||
export function getNxProjectJsonPlugin(root: string): NxPluginV2 {
|
||||
return {
|
||||
@@ -13,6 +21,7 @@ export function getNxProjectJsonPlugin(root: string): NxPluginV2 {
|
||||
(file) => {
|
||||
const json = readJsonFile<ProjectConfiguration>(join(root, file));
|
||||
const project = buildProjectFromProjectJson(json, file);
|
||||
mergePackageJsonConfigurationWithProjectJson(project, root);
|
||||
return {
|
||||
projects: {
|
||||
[project.name]: project,
|
||||
@@ -33,3 +42,46 @@ export function buildProjectFromProjectJson(
|
||||
...json,
|
||||
};
|
||||
}
|
||||
|
||||
export function mergePackageJsonConfigurationWithProjectJson(
|
||||
p: ProjectConfiguration,
|
||||
root: string
|
||||
) {
|
||||
if (existsSync(join(root, p.root, 'package.json'))) {
|
||||
try {
|
||||
const packageJson: PackageJson = readJsonFile(
|
||||
join(root, p.root, 'package.json')
|
||||
);
|
||||
|
||||
p.targets = mergeNpmScriptsWithTargets(packageJson, p.targets);
|
||||
|
||||
const { nx } = packageJson;
|
||||
|
||||
if (nx?.tags) {
|
||||
p.tags = [...(p.tags || []), ...nx.tags];
|
||||
}
|
||||
if (nx?.implicitDependencies) {
|
||||
p.implicitDependencies = [
|
||||
...(p.implicitDependencies || []),
|
||||
...nx.implicitDependencies,
|
||||
];
|
||||
}
|
||||
if (nx?.namedInputs) {
|
||||
p.namedInputs = { ...(p.namedInputs || {}), ...nx.namedInputs };
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore json parser errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function mergeNpmScriptsWithTargets(
|
||||
packageJson: PackageJson,
|
||||
targets: Record<string, TargetConfiguration>
|
||||
): Record<string, TargetConfiguration> {
|
||||
try {
|
||||
return { ...readTargetsFromPackageJson(packageJson), ...(targets || {}) };
|
||||
} catch (e) {
|
||||
return targets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://nx.dev/core-concepts/configuration#nxjson",
|
||||
"$id": "https://nx.dev/reference/nx-json",
|
||||
"title": "JSON schema for Nx configuration",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"$id": "https://nx.dev/project-schema",
|
||||
"$id": "https://nx.dev/reference/project-configuration",
|
||||
"title": "JSON schema for Nx projects",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -1,10 +1,20 @@
|
||||
import { existsSync } from 'fs';
|
||||
import * as path from 'path';
|
||||
import { readJsonFile } from '../utils/fileutils';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../config/workspace-json-project-json';
|
||||
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
|
||||
import { NxPluginV2 } from '../devkit-exports';
|
||||
|
||||
export const NX_ANGULAR_JSON_PLUGIN_NAME = 'nx-angular-json-plugin';
|
||||
|
||||
export const NxAngularJsonPlugin: NxPluginV2 = {
|
||||
name: NX_ANGULAR_JSON_PLUGIN_NAME,
|
||||
createNodes: [
|
||||
'angular.json',
|
||||
(f, ctx) => ({
|
||||
projects: readAngularJson(ctx.workspaceRoot),
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
export function shouldMergeAngularProjects(
|
||||
root: string,
|
||||
@@ -45,25 +55,6 @@ function readAngularJson(angularCliWorkspaceRoot: string) {
|
||||
).projects;
|
||||
}
|
||||
|
||||
export function mergeAngularJsonAndProjects(
|
||||
projects: {
|
||||
[name: string]: ProjectConfiguration;
|
||||
},
|
||||
angularCliWorkspaceRoot: string
|
||||
): { [name: string]: ProjectConfiguration } {
|
||||
const res = readAngularJson(angularCliWorkspaceRoot);
|
||||
const folders = new Set();
|
||||
for (let k of Object.keys(res)) {
|
||||
folders.add(res[k].root);
|
||||
}
|
||||
for (let k of Object.keys(projects)) {
|
||||
if (!folders.has(projects[k].root)) {
|
||||
res[k] = projects[k];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
export function toNewFormat(w: any): ProjectsConfigurations {
|
||||
Object.values(w.projects || {}).forEach((projectConfig: any) => {
|
||||
if (projectConfig.architect) {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { logger } from '../utils/logger';
|
||||
import {
|
||||
createProjectGraphAsync,
|
||||
readProjectsConfigurationFromProjectGraph,
|
||||
|
||||
@@ -44,7 +44,7 @@ export function calculateDefaultProjectName(
|
||||
}
|
||||
|
||||
export function findMatchingProjectInCwd(
|
||||
projects: { [projectName: string]: ProjectConfiguration },
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
relativeCwd: string
|
||||
): string | undefined {
|
||||
const projectRootMappings = new Map<string, string>();
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
import { Workspaces } from './workspaces';
|
||||
import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { NxJsonConfiguration } from './nx-json';
|
||||
import { ProjectsConfigurations } from './workspace-json-project-json';
|
||||
import { readNxJson } from './nx-json';
|
||||
|
||||
// TODO(vsavkin): Remove after Nx 16 is out
|
||||
/**
|
||||
* @deprecated Use readProjectsConfigurationFromProjectGraph(await createProjectGraphAsync())
|
||||
*/
|
||||
export function readAllWorkspaceConfiguration(): ProjectsConfigurations &
|
||||
NxJsonConfiguration {
|
||||
return new Workspaces(workspaceRoot).readProjectsConfigurations();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about where apps and libs will be created.
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import { toProjectName, Workspaces } from './workspaces';
|
||||
import { TempFs } from '../utils/testing/temp-fs';
|
||||
import { withEnvironmentVariables } from '../../internal-testing-utils/with-environment';
|
||||
import { retrieveProjectConfigurations } from '../project-graph/utils/retrieve-workspace-files';
|
||||
import { readNxJson } from './configuration';
|
||||
|
||||
const libConfig = (root, name?: string) => ({
|
||||
name: name ?? toProjectName(`${root}/some-file`),
|
||||
projectType: 'library',
|
||||
root: `libs/${root}`,
|
||||
sourceRoot: `libs/${root}/src`,
|
||||
targets: {},
|
||||
});
|
||||
|
||||
const packageLibConfig = (root, name?: string) => ({
|
||||
@@ -14,6 +17,7 @@ const packageLibConfig = (root, name?: string) => ({
|
||||
root,
|
||||
sourceRoot: root,
|
||||
projectType: 'library',
|
||||
targets: {},
|
||||
});
|
||||
|
||||
describe('Workspaces', () => {
|
||||
@@ -45,7 +49,7 @@ describe('Workspaces', () => {
|
||||
});
|
||||
|
||||
const workspaces = new Workspaces(fs.tempDir);
|
||||
const resolved = workspaces.readProjectsConfigurations();
|
||||
const resolved = workspaces.readWorkspaceConfiguration();
|
||||
expect(resolved.projects.lib1).toEqual(standaloneConfig);
|
||||
});
|
||||
|
||||
@@ -74,7 +78,7 @@ describe('Workspaces', () => {
|
||||
});
|
||||
|
||||
const workspaces = new Workspaces(fs.tempDir);
|
||||
const { projects } = workspaces.readProjectsConfigurations();
|
||||
const { projects } = workspaces.readWorkspaceConfiguration();
|
||||
|
||||
// projects got merged for lib1
|
||||
expect(projects['lib1']).toEqual({
|
||||
@@ -82,6 +86,7 @@ describe('Workspaces', () => {
|
||||
root: 'libs/lib1',
|
||||
sourceRoot: 'libs/lib1/src',
|
||||
projectType: 'library',
|
||||
targets: {},
|
||||
});
|
||||
expect(projects.lib2).toEqual(lib2Config);
|
||||
expect(projects['domain-lib3']).toEqual(domainPackageConfig);
|
||||
@@ -112,14 +117,17 @@ describe('Workspaces', () => {
|
||||
{
|
||||
NX_WORKSPACE_ROOT: fs.tempDir,
|
||||
},
|
||||
() => {
|
||||
const workspaces = new Workspaces(fs.tempDir);
|
||||
const resolved = workspaces.readProjectsConfigurations();
|
||||
expect(resolved.projects['my-package']).toEqual({
|
||||
async () => {
|
||||
const resolved = await retrieveProjectConfigurations(
|
||||
fs.tempDir,
|
||||
readNxJson(fs.tempDir)
|
||||
);
|
||||
expect(resolved.projectNodes['my-package']).toEqual({
|
||||
name: 'my-package',
|
||||
root: 'packages/my-package',
|
||||
sourceRoot: 'packages/my-package',
|
||||
projectType: 'library',
|
||||
targets: {},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,110 +1,29 @@
|
||||
import { dirname, join } from 'path';
|
||||
import { workspaceRoot } from '../utils/workspace-root';
|
||||
import { readJsonFile } from '../utils/fileutils';
|
||||
import { getNxRequirePaths } from '../utils/installation-directory';
|
||||
import { loadNxPlugins, loadNxPluginsSync } from '../utils/nx-plugin';
|
||||
import { dirname } from 'path';
|
||||
|
||||
import type { NxJsonConfiguration } from './nx-json';
|
||||
import { readNxJson } from './nx-json';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from './workspace-json-project-json';
|
||||
import {
|
||||
mergeAngularJsonAndProjects,
|
||||
shouldMergeAngularProjects,
|
||||
} from '../adapter/angular-json';
|
||||
import { retrieveProjectConfigurationPaths } from '../project-graph/utils/retrieve-workspace-files';
|
||||
import {
|
||||
buildProjectsConfigurationsFromProjectPathsAndPlugins,
|
||||
mergeTargetConfigurations,
|
||||
readTargetDefaultsForTarget,
|
||||
} from '../project-graph/utils/project-configuration-utils';
|
||||
import { ProjectsConfigurations } from './workspace-json-project-json';
|
||||
import { retrieveProjectConfigurationsSync } from '../project-graph/utils/retrieve-workspace-files';
|
||||
|
||||
// TODO(v18): remove this class
|
||||
/**
|
||||
* @deprecated This will be removed in v18. Use {@link readProjectsConfigurationFromProjectGraph} instead.
|
||||
*/
|
||||
export class Workspaces {
|
||||
private cachedProjectsConfig: ProjectsConfigurations;
|
||||
|
||||
constructor(private root: string) {}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* @deprecated Use {@link readProjectsConfigurationFromProjectGraph} instead.
|
||||
*/
|
||||
readProjectsConfigurations(opts?: {
|
||||
_includeProjectsFromAngularJson?: boolean;
|
||||
}): ProjectsConfigurations {
|
||||
if (
|
||||
this.cachedProjectsConfig &&
|
||||
process.env.NX_CACHE_PROJECTS_CONFIG !== 'false'
|
||||
) {
|
||||
return this.cachedProjectsConfig;
|
||||
}
|
||||
readWorkspaceConfiguration(): ProjectsConfigurations & NxJsonConfiguration {
|
||||
const nxJson = readNxJson(this.root);
|
||||
const projectPaths = retrieveProjectConfigurationPaths(this.root, nxJson);
|
||||
let projectsConfigurations =
|
||||
buildProjectsConfigurationsFromProjectPathsAndPlugins(
|
||||
nxJson,
|
||||
projectPaths,
|
||||
loadNxPluginsSync(
|
||||
nxJson.plugins,
|
||||
getNxRequirePaths(this.root),
|
||||
this.root
|
||||
),
|
||||
this.root
|
||||
).projects;
|
||||
if (
|
||||
shouldMergeAngularProjects(
|
||||
this.root,
|
||||
opts?._includeProjectsFromAngularJson
|
||||
)
|
||||
) {
|
||||
projectsConfigurations = mergeAngularJsonAndProjects(
|
||||
projectsConfigurations,
|
||||
this.root
|
||||
);
|
||||
}
|
||||
this.cachedProjectsConfig = {
|
||||
|
||||
return {
|
||||
version: 2,
|
||||
projects: projectsConfigurations,
|
||||
projects: retrieveProjectConfigurationsSync(this.root, nxJson)
|
||||
.projectNodes,
|
||||
...nxJson,
|
||||
};
|
||||
return this.cachedProjectsConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated. Use readProjectsConfigurations
|
||||
*/
|
||||
readWorkspaceConfiguration(opts?: {
|
||||
_ignorePluginInference?: boolean;
|
||||
_includeProjectsFromAngularJson?: boolean;
|
||||
}): ProjectsConfigurations & NxJsonConfiguration {
|
||||
const nxJson = readNxJson(this.root);
|
||||
return { ...this.readProjectsConfigurations(opts), ...nxJson };
|
||||
}
|
||||
|
||||
private mergeTargetDefaultsIntoProjectDescriptions(
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
nxJson: NxJsonConfiguration
|
||||
) {
|
||||
for (const proj of Object.values(projects)) {
|
||||
if (proj.targets) {
|
||||
for (const targetName of Object.keys(proj.targets ?? {})) {
|
||||
const projectTargetDefinition = proj.targets[targetName];
|
||||
const defaults = readTargetDefaultsForTarget(
|
||||
targetName,
|
||||
nxJson.targetDefaults,
|
||||
projectTargetDefinition.executor
|
||||
);
|
||||
|
||||
if (defaults) {
|
||||
proj.targets[targetName] = mergeTargetConfigurations(
|
||||
proj,
|
||||
targetName,
|
||||
defaults
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
import { fileExists } from '../../utils/fileutils';
|
||||
import { notifyFileWatcherSockets } from './file-watching/file-watcher-sockets';
|
||||
import { serverLogger } from './logger';
|
||||
import { Workspaces } from '../../config/workspaces';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
import { execSync } from 'child_process';
|
||||
import { fileHasher, hashArray } from '../../hasher/file-hasher';
|
||||
@@ -23,7 +22,10 @@ import {
|
||||
retrieveWorkspaceFiles,
|
||||
retrieveProjectConfigurations,
|
||||
} from '../../project-graph/utils/retrieve-workspace-files';
|
||||
import { ProjectConfiguration } from '../../config/workspace-json-project-json';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import { readNxJson } from '../../config/nx-json';
|
||||
|
||||
let cachedSerializedProjectGraphPromise: Promise<{
|
||||
@@ -173,7 +175,7 @@ async function processCollectedUpdatedAndDeletedFiles() {
|
||||
);
|
||||
fileHasher.incrementalUpdate(updatedFiles, deletedFiles);
|
||||
|
||||
let nxJson = readNxJson(workspaceRoot);
|
||||
const nxJson = readNxJson(workspaceRoot);
|
||||
|
||||
const { projectNodes } = await retrieveProjectConfigurations(
|
||||
workspaceRoot,
|
||||
@@ -264,16 +266,17 @@ async function createAndSerializeProjectGraph(): Promise<{
|
||||
}> {
|
||||
try {
|
||||
performance.mark('create-project-graph-start');
|
||||
const projectsConfigurations = new Workspaces(
|
||||
workspaceRoot
|
||||
).readProjectsConfigurations();
|
||||
const projectConfigurations = await retrieveProjectConfigurations(
|
||||
workspaceRoot,
|
||||
readNxJson(workspaceRoot)
|
||||
);
|
||||
const projectFileMap = copyFileMap(projectFileMapWithFiles.projectFileMap);
|
||||
const allWorkspaceFiles = copyFileData(
|
||||
projectFileMapWithFiles.allWorkspaceFiles
|
||||
);
|
||||
const { projectGraph, projectFileMapCache } =
|
||||
await buildProjectGraphUsingProjectFileMap(
|
||||
projectsConfigurations,
|
||||
projectConfigurations.projectNodes,
|
||||
knownExternalNodes,
|
||||
projectFileMap,
|
||||
allWorkspaceFiles,
|
||||
|
||||
@@ -37,15 +37,13 @@ export type {
|
||||
HasherContext,
|
||||
} from './config/misc-interfaces';
|
||||
|
||||
// TODO(v18): Remove this export
|
||||
/**
|
||||
* @category Workspace
|
||||
*/
|
||||
export { Workspaces } from './config/workspaces';
|
||||
|
||||
export {
|
||||
readAllWorkspaceConfiguration,
|
||||
workspaceLayout,
|
||||
} from './config/configuration';
|
||||
export { workspaceLayout } from './config/configuration';
|
||||
|
||||
export type {
|
||||
NxPlugin,
|
||||
@@ -208,6 +206,7 @@ export { reverse } from './project-graph/operators';
|
||||
export {
|
||||
createProjectGraphAsync,
|
||||
readCachedProjectGraph,
|
||||
readProjectsConfigurationFromProjectGraph,
|
||||
} from './project-graph/project-graph';
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,3 +7,9 @@ export { createTempNpmDirectory } from './utils/package-manager';
|
||||
export { getExecutorInformation } from './command-line/run/executor-utils';
|
||||
export { readNxJson as readNxJsonFromDisk } from './config/nx-json';
|
||||
export { calculateDefaultProjectName } from './config/calculate-default-project-name';
|
||||
export { retrieveProjectConfigurationsWithAngularProjects } from './project-graph/utils/retrieve-workspace-files';
|
||||
export { splitTarget } from './utils/split-target';
|
||||
export { combineOptionsForExecutor } from './utils/params';
|
||||
export { sortObjectByKeys } from './utils/object-sort';
|
||||
export { stripIndent } from './utils/logger';
|
||||
export { readModulePackageJson } from './utils/package-json';
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
*/
|
||||
|
||||
import type { Observable } from 'rxjs';
|
||||
import { Workspaces } from '../../config/workspaces';
|
||||
import { readNxJson } from '../../config/nx-json';
|
||||
import { Executor, ExecutorContext } from '../../config/misc-interfaces';
|
||||
import { retrieveProjectConfigurations } from '../../project-graph/utils/retrieve-workspace-files';
|
||||
import { ProjectsConfigurations } from '../../config/workspace-json-project-json';
|
||||
|
||||
/**
|
||||
* Convert an Nx Executor into an Angular Devkit Builder
|
||||
@@ -14,11 +15,17 @@ import { Executor, ExecutorContext } from '../../config/misc-interfaces';
|
||||
*/
|
||||
export function convertNxExecutor(executor: Executor) {
|
||||
const builderFunction = (options, builderContext) => {
|
||||
const workspaces = new Workspaces(builderContext.workspaceRoot);
|
||||
const projectsConfigurations = workspaces.readProjectsConfigurations();
|
||||
|
||||
const promise = async () => {
|
||||
const nxJsonConfiguration = readNxJson(builderContext.workspaceRoot);
|
||||
const projectsConfigurations: ProjectsConfigurations = {
|
||||
version: 2,
|
||||
projects: (
|
||||
await retrieveProjectConfigurations(
|
||||
builderContext.workspaceRoot,
|
||||
nxJsonConfiguration
|
||||
)
|
||||
).projectNodes,
|
||||
};
|
||||
const context: ExecutorContext = {
|
||||
root: builderContext.workspaceRoot,
|
||||
projectName: builderContext.target.project,
|
||||
|
||||
@@ -10,7 +10,10 @@ import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import { mergeProjectConfigurationIntoProjectsConfigurations } from '../../project-graph/utils/project-configuration-utils';
|
||||
import {
|
||||
mergeProjectConfigurationIntoRootMap,
|
||||
readProjectConfigurationsFromRootMap,
|
||||
} from '../../project-graph/utils/project-configuration-utils';
|
||||
import { retrieveProjectConfigurationPathsWithoutPluginInference } from '../../project-graph/utils/retrieve-workspace-files';
|
||||
import { output } from '../../utils/output';
|
||||
import { PackageJson } from '../../utils/package-json';
|
||||
@@ -183,8 +186,6 @@ export function getRelativeProjectJsonSchemaPath(
|
||||
function readAndCombineAllProjectConfigurations(tree: Tree): {
|
||||
[name: string]: ProjectConfiguration;
|
||||
} {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
/**
|
||||
* We can't update projects that come from plugins anyways, so we are going
|
||||
* to ignore them for now. Plugins should add their own add/create/update methods
|
||||
@@ -207,17 +208,12 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
|
||||
(r) => deletedFiles.indexOf(r) === -1
|
||||
);
|
||||
|
||||
const rootMap: Map<string, string> = new Map();
|
||||
return projectFiles.reduce((projects, projectFile) => {
|
||||
const rootMap: Map<string, ProjectConfiguration> = new Map();
|
||||
for (const projectFile of projectFiles) {
|
||||
if (basename(projectFile) === 'project.json') {
|
||||
const json = readJson(tree, projectFile);
|
||||
const config = buildProjectFromProjectJson(json, projectFile);
|
||||
mergeProjectConfigurationIntoProjectsConfigurations(
|
||||
projects,
|
||||
rootMap,
|
||||
config,
|
||||
projectFile
|
||||
);
|
||||
mergeProjectConfigurationIntoRootMap(rootMap, config, projectFile);
|
||||
} else {
|
||||
const packageJson = readJson<PackageJson>(tree, projectFile);
|
||||
const config = buildProjectConfigurationFromPackageJson(
|
||||
@@ -225,8 +221,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
|
||||
projectFile,
|
||||
readNxJson(tree)
|
||||
);
|
||||
mergeProjectConfigurationIntoProjectsConfigurations(
|
||||
projects,
|
||||
mergeProjectConfigurationIntoRootMap(
|
||||
rootMap,
|
||||
// Inferred targets, tags, etc don't show up when running generators
|
||||
// This is to help avoid running into issues when trying to update the workspace
|
||||
@@ -237,8 +232,9 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
|
||||
projectFile
|
||||
);
|
||||
}
|
||||
return projects;
|
||||
}, {});
|
||||
}
|
||||
|
||||
return readProjectConfigurationsFromRootMap(rootMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -743,6 +743,7 @@ class TaskHasherImpl {
|
||||
runtime,
|
||||
{
|
||||
windowsHide: true,
|
||||
cwd: workspaceRoot,
|
||||
},
|
||||
(err, stdout, stderr) => {
|
||||
if (err) {
|
||||
|
||||
+11
-2
@@ -1,9 +1,14 @@
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use fs_extra::error::ErrorKind;
|
||||
|
||||
#[napi]
|
||||
pub fn remove(src: String) -> anyhow::Result<()> {
|
||||
fs_extra::remove_items(&[src]).map_err(anyhow::Error::from)
|
||||
fs_extra::remove_items(&[src]).map_err(|err| match err.kind {
|
||||
ErrorKind::Io(err_kind) => anyhow::Error::new(err_kind),
|
||||
_ => anyhow::Error::new(err),
|
||||
})
|
||||
}
|
||||
|
||||
#[napi]
|
||||
@@ -19,7 +24,11 @@ pub fn copy(src: String, dest: String) -> anyhow::Result<()> {
|
||||
fs::create_dir_all(dest_parent)?;
|
||||
}
|
||||
|
||||
fs_extra::copy_items(&[src], dest_parent, ©_options)?;
|
||||
fs_extra::copy_items(&[src], dest_parent, ©_options).map_err(|err| match err.kind {
|
||||
ErrorKind::Io(err_kind) => anyhow::Error::new(err_kind),
|
||||
_ => anyhow::Error::new(err),
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ use std::path::PathBuf;
|
||||
use tracing::trace;
|
||||
use watchexec_events::{Event, Tag};
|
||||
|
||||
use crate::native::watch::utils::transform_event;
|
||||
|
||||
#[napi(string_enum)]
|
||||
#[derive(Debug)]
|
||||
/// Newly created files will have the `update` EventType as well.
|
||||
@@ -52,6 +54,9 @@ pub(super) struct WatchEventInternal {
|
||||
|
||||
impl From<&Event> for WatchEventInternal {
|
||||
fn from(value: &Event) -> Self {
|
||||
let transformed = transform_event(value);
|
||||
let value = transformed.as_ref().unwrap_or(value);
|
||||
|
||||
let path = value.paths().next().expect("there should always be a path");
|
||||
|
||||
let event_kind = value
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use ignore::WalkBuilder;
|
||||
use ignore_files::IgnoreFile;
|
||||
use std::path::PathBuf;
|
||||
use once_cell::sync::Lazy;
|
||||
use os_type::{OSInformation, OSType};
|
||||
use std::{fs, path::PathBuf};
|
||||
use tracing::trace;
|
||||
use watchexec_events::{Event, Tag};
|
||||
|
||||
pub(super) fn get_ignore_files<T: AsRef<str>>(root: T) -> Vec<IgnoreFile> {
|
||||
let root = root.as_ref();
|
||||
@@ -45,3 +49,34 @@ pub(super) fn get_ignore_files<T: AsRef<str>>(root: T) -> Vec<IgnoreFile> {
|
||||
// .map(|result| result.path().into())
|
||||
// .collect()
|
||||
// }
|
||||
|
||||
static OS_PLATFORM: Lazy<OSInformation> = Lazy::new(os_type::current_platform);
|
||||
|
||||
pub(super) fn transform_event(watch_event: &Event) -> Option<Event> {
|
||||
if OS_PLATFORM.os_type == OSType::Debian {
|
||||
let tags = watch_event
|
||||
.tags
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|tag| match tag {
|
||||
Tag::Path { path, file_type } => {
|
||||
trace!("canonicalizing {:?}", path);
|
||||
let real_path = fs::canonicalize(&path).unwrap_or(path);
|
||||
trace!("real path {:?}", real_path);
|
||||
Tag::Path {
|
||||
path: real_path,
|
||||
file_type,
|
||||
}
|
||||
}
|
||||
_ => tag,
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(Event {
|
||||
tags,
|
||||
metadata: watch_event.metadata.clone(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ use watchexec_events::filekind::{CreateKind, FileEventKind, ModifyKind, RemoveKi
|
||||
use watchexec_events::{Event, FileType, Priority, Source, Tag};
|
||||
use watchexec_filterer_ignore::IgnoreFilterer;
|
||||
|
||||
use crate::native::watch::utils::transform_event;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WatchFilterer {
|
||||
pub inner: IgnoreFilterer,
|
||||
@@ -13,7 +15,10 @@ pub struct WatchFilterer {
|
||||
|
||||
/// Used to filter out events that that come from watchexec
|
||||
impl Filterer for WatchFilterer {
|
||||
fn check_event(&self, event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
||||
fn check_event(&self, watch_event: &Event, priority: Priority) -> Result<bool, RuntimeError> {
|
||||
let transformed = transform_event(watch_event);
|
||||
let event = transformed.as_ref().unwrap_or(watch_event);
|
||||
|
||||
if !self.inner.check_event(event, priority)? {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
@@ -34,11 +34,15 @@ export const processProjectGraph: ProjectGraphProcessor = async (
|
||||
let parsedLockFile: ProjectGraph;
|
||||
if (lockFileNeedsReprocessing(lockHash)) {
|
||||
parsedLockFile = parseLockFile();
|
||||
writeLastProcessedLockfileHash(lockHash, parsedLockFile);
|
||||
if (parsedLockFile) {
|
||||
writeLastProcessedLockfileHash(lockHash, parsedLockFile);
|
||||
}
|
||||
} else {
|
||||
parsedLockFile = readParsedLockFile();
|
||||
}
|
||||
builder.mergeProjectGraph(parsedLockFile);
|
||||
if (parsedLockFile) {
|
||||
builder.mergeProjectGraph(parsedLockFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -365,6 +365,11 @@ describe('yarn LockFile utility', () => {
|
||||
'node_modules/yargs/package.json': '{"version": "17.6.2"}',
|
||||
'node_modules/yargs-parser/package.json': '{"version": "21.1.1"}',
|
||||
'node_modules/yocto-queue/package.json': '{"version": "0.1.0"}',
|
||||
'node_modules/@types/prop-types/package.json': '{"version": "15.7.5"}',
|
||||
'node_modules/@docusaurus/core/package.json': '{"version": "2.4.1"}',
|
||||
'node_modules/@docusaurus/react-loadable/package.json':
|
||||
'{"version": "5.5.2"}',
|
||||
'node_modules/react-loadable/package.json': '{"version": "5.5.2"}',
|
||||
};
|
||||
vol.fromJSON(fileSys, '/root');
|
||||
});
|
||||
@@ -620,6 +625,145 @@ describe('yarn LockFile utility', () => {
|
||||
prunedLockFile.split('\n').slice(2)
|
||||
);
|
||||
});
|
||||
|
||||
describe('alias duplicate', () => {
|
||||
it('should parse yarn berry', async () => {
|
||||
const lockFile = `# This file is generated by running "yarn install" inside your project.
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 6
|
||||
cacheKey: 8
|
||||
|
||||
"@docusaurus/core@npm:2.4.1":
|
||||
version: 2.4.1
|
||||
resolution: "@docusaurus/core@npm:2.4.1"
|
||||
dependencies:
|
||||
"@docusaurus/react-loadable": 5.5.2
|
||||
react-loadable: "npm:@docusaurus/react-loadable@5.5.2"
|
||||
bin:
|
||||
docusaurus: bin/docusaurus.mjs
|
||||
checksum: 40c887ef662f7679d803695d4193268c2c177c6d4e13b43b56cc519322522a1608b4bfc4999f6355be778ca7a0256f0d27ab18a19b352a9da1aed66e2644dc82
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@docusaurus/react-loadable@npm:5.5.2, react-loadable@npm:@docusaurus/react-loadable@5.5.2":
|
||||
version: 5.5.2
|
||||
resolution: "@docusaurus/react-loadable@npm:5.5.2"
|
||||
checksum: 930fb9e2936412a12461f210acdc154a433283921ca43ac3fc3b84cb6c12eb738b3a3719373022bf68004efeb1a928dbe36c467d7a1f86454ed6241576d936e7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
`;
|
||||
|
||||
const packageJson: PackageJson = {
|
||||
name: '@my-ns/example',
|
||||
version: '0.0.1',
|
||||
type: 'commonjs',
|
||||
dependencies: {
|
||||
'@docusaurus/core': '2.4.1',
|
||||
},
|
||||
};
|
||||
|
||||
const builder = new ProjectGraphBuilder();
|
||||
parseYarnLockfile(lockFile, packageJson, builder);
|
||||
const graph = builder.getUpdatedProjectGraph();
|
||||
expect(graph.externalNodes).toMatchInlineSnapshot(`
|
||||
{
|
||||
"npm:@docusaurus/core": {
|
||||
"data": {
|
||||
"hash": "40c887ef662f7679d803695d4193268c2c177c6d4e13b43b56cc519322522a1608b4bfc4999f6355be778ca7a0256f0d27ab18a19b352a9da1aed66e2644dc82",
|
||||
"packageName": "@docusaurus/core",
|
||||
"version": "2.4.1",
|
||||
},
|
||||
"name": "npm:@docusaurus/core",
|
||||
"type": "npm",
|
||||
},
|
||||
"npm:@docusaurus/react-loadable": {
|
||||
"data": {
|
||||
"hash": "930fb9e2936412a12461f210acdc154a433283921ca43ac3fc3b84cb6c12eb738b3a3719373022bf68004efeb1a928dbe36c467d7a1f86454ed6241576d936e7",
|
||||
"packageName": "@docusaurus/react-loadable",
|
||||
"version": "5.5.2",
|
||||
},
|
||||
"name": "npm:@docusaurus/react-loadable",
|
||||
"type": "npm",
|
||||
},
|
||||
"npm:react-loadable": {
|
||||
"data": {
|
||||
"hash": "930fb9e2936412a12461f210acdc154a433283921ca43ac3fc3b84cb6c12eb738b3a3719373022bf68004efeb1a928dbe36c467d7a1f86454ed6241576d936e7",
|
||||
"packageName": "react-loadable",
|
||||
"version": "npm:@docusaurus/react-loadable@5.5.2",
|
||||
},
|
||||
"name": "npm:react-loadable",
|
||||
"type": "npm",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should parse yarn classic', async () => {
|
||||
const lockFile = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@docusaurus/core@2.4.1":
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@docusaurus/core/-/core-2.4.1.tgz#4b8ff5766131ce3fbccaad0b1daf2ad4dc76f62d"
|
||||
integrity sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==
|
||||
dependencies:
|
||||
"@docusaurus/react-loadable" "5.5.2"
|
||||
react-loadable "npm:@docusaurus/react-loadable@5.5.2"
|
||||
|
||||
"@docusaurus/react-loadable@5.5.2", "react-loadable@npm:@docusaurus/react-loadable@5.5.2":
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/@docusaurus/react-loadable/-/react-loadable-5.5.2.tgz#81aae0db81ecafbdaee3651f12804580868fa6ce"
|
||||
integrity sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==
|
||||
`;
|
||||
|
||||
const packageJson: PackageJson = {
|
||||
name: '@my-ns/example',
|
||||
version: '0.0.1',
|
||||
type: 'commonjs',
|
||||
dependencies: {
|
||||
'@docusaurus/core': '2.4.1',
|
||||
},
|
||||
};
|
||||
|
||||
const builder = new ProjectGraphBuilder();
|
||||
parseYarnLockfile(lockFile, packageJson, builder);
|
||||
const graph = builder.getUpdatedProjectGraph();
|
||||
expect(graph.externalNodes).toMatchInlineSnapshot(`
|
||||
{
|
||||
"npm:@docusaurus/core": {
|
||||
"data": {
|
||||
"hash": "sha512-SNsY7PshK3Ri7vtsLXVeAJGS50nJN3RgF836zkyUfAD01Fq+sAk5EwWgLw+nnm5KVNGDu7PRR2kRGDsWvqpo0g==",
|
||||
"packageName": "@docusaurus/core",
|
||||
"version": "2.4.1",
|
||||
},
|
||||
"name": "npm:@docusaurus/core",
|
||||
"type": "npm",
|
||||
},
|
||||
"npm:@docusaurus/react-loadable": {
|
||||
"data": {
|
||||
"hash": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
|
||||
"packageName": "@docusaurus/react-loadable",
|
||||
"version": "5.5.2",
|
||||
},
|
||||
"name": "npm:@docusaurus/react-loadable",
|
||||
"type": "npm",
|
||||
},
|
||||
"npm:react-loadable": {
|
||||
"data": {
|
||||
"hash": "sha512-A3dYjdBGuy0IGT+wyLIGIKLRE+sAk1iNk0f1HjNDysO7u8lhL4N3VEm+FAubmJbAztn94F7MxBTPmnixbiyFdQ==",
|
||||
"packageName": "react-loadable",
|
||||
"version": "npm:@docusaurus/react-loadable@5.5.2",
|
||||
},
|
||||
"name": "npm:react-loadable",
|
||||
"type": "npm",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('auxiliary tagged version ranges', () => {
|
||||
|
||||
@@ -50,13 +50,17 @@ export function parseYarnLockfile(
|
||||
addDependencies(groupedDependencies, builder, keyMap);
|
||||
}
|
||||
|
||||
function getPackageNames(keys: string): string[] {
|
||||
const packageNames = new Set<string>();
|
||||
function getPackageNameKeyPairs(keys: string): Map<string, Set<string>> {
|
||||
const result = new Map<string, Set<string>>();
|
||||
keys.split(', ').forEach((key) => {
|
||||
const packageName = key.slice(0, key.indexOf('@', 1));
|
||||
packageNames.add(packageName);
|
||||
if (result.has(packageName)) {
|
||||
result.get(packageName).add(key);
|
||||
} else {
|
||||
result.set(packageName, new Set([key]));
|
||||
}
|
||||
});
|
||||
return Array.from(packageNames);
|
||||
return result;
|
||||
}
|
||||
|
||||
function addNodes(
|
||||
@@ -79,16 +83,14 @@ function addNodes(
|
||||
if (snapshot.linkType === 'soft' || keys.includes('@patch:')) {
|
||||
return;
|
||||
}
|
||||
const packageNames = getPackageNames(keys);
|
||||
packageNames.forEach((packageName) => {
|
||||
const version = findVersion(
|
||||
packageName,
|
||||
keys.split(', ')[0],
|
||||
snapshot,
|
||||
isBerry
|
||||
);
|
||||
const nameKeyPairs = getPackageNameKeyPairs(keys);
|
||||
nameKeyPairs.forEach((keySet, packageName) => {
|
||||
const keysArray = Array.from(keySet);
|
||||
// use key relevant to the package name
|
||||
const version = findVersion(packageName, keysArray[0], snapshot, isBerry);
|
||||
|
||||
keys.split(', ').forEach((key) => {
|
||||
// use keys linked to the extracted package name
|
||||
keysArray.forEach((key) => {
|
||||
// we don't need to keep duplicates, we can just track the keys
|
||||
const existingNode = nodes.get(packageName)?.get(version);
|
||||
if (existingNode) {
|
||||
@@ -182,11 +184,12 @@ function findVersion(
|
||||
snapshot: YarnDependency,
|
||||
isBerry: boolean
|
||||
): string {
|
||||
const versionRange = key.slice(packageName.length + 1);
|
||||
const versionRange = key.slice(key.indexOf('@', 1) + 1);
|
||||
// check for alias packages
|
||||
const isAlias = isBerry
|
||||
? snapshot.resolution && !snapshot.resolution.startsWith(`${packageName}@`)
|
||||
: versionRange.startsWith('npm:');
|
||||
|
||||
if (isAlias) {
|
||||
return versionRange;
|
||||
}
|
||||
|
||||
+4
-1
@@ -587,7 +587,10 @@ async function createVirtualWorkspace(config: VirtualWorkspaceConfig) {
|
||||
|
||||
return {
|
||||
ctx: {
|
||||
projectsConfigurations: projectConfigurations,
|
||||
projectsConfigurations: {
|
||||
version: 2,
|
||||
projectConfigurations: projectConfigurations,
|
||||
},
|
||||
nxJsonConfiguration: nxJson,
|
||||
filesToProcess: projectFileMap,
|
||||
},
|
||||
|
||||
@@ -312,6 +312,32 @@ describe('workspace-projects', () => {
|
||||
).toEqual({ a: 'a', b: 'my/project' });
|
||||
});
|
||||
|
||||
it('should merge options when targets use executors with defaults', () => {
|
||||
expect(
|
||||
normalizeProjectTargets(
|
||||
{
|
||||
root: 'my/project',
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/jest:jest',
|
||||
options: {
|
||||
a: 'a',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
'@nx/jest:jest': {
|
||||
options: {
|
||||
b: 'b',
|
||||
},
|
||||
},
|
||||
},
|
||||
'build'
|
||||
).build.options
|
||||
).toEqual({ a: 'a', b: 'b' });
|
||||
});
|
||||
|
||||
it('should not merge options when targets use different executors', () => {
|
||||
expect(
|
||||
normalizeProjectTargets(
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { join } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
import {
|
||||
ProjectGraphProcessorContext,
|
||||
ProjectGraphProjectNode,
|
||||
} from '../../config/project-graph';
|
||||
import { mergeNpmScriptsWithTargets } from '../../utils/project-graph-utils';
|
||||
import { ProjectGraphBuilder } from '../project-graph-builder';
|
||||
import { PackageJson } from '../../utils/package-json';
|
||||
import { readJsonFile } from '../../utils/fileutils';
|
||||
import { NxJsonConfiguration } from '../../config/nx-json';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
@@ -45,36 +41,6 @@ export async function normalizeProjectNodes(
|
||||
|
||||
for (const key of projects) {
|
||||
const p = ctx.projectsConfigurations.projects[key];
|
||||
const projectRoot = join(workspaceRoot, p.root);
|
||||
|
||||
// Todo(@AgentEnder) we can move a lot of this to
|
||||
// builtin plugin inside workspaces.ts, but there would be some functional differences
|
||||
// - The plugin would only apply to package.json files found via the workspaces globs
|
||||
// - This means that scripts / tags / etc from the `nx` property wouldn't be read if a project
|
||||
// is being found by project.json and not included in the workspaces configuration. Maybe this is fine?
|
||||
if (existsSync(join(projectRoot, 'package.json'))) {
|
||||
p.targets = mergeNpmScriptsWithTargets(projectRoot, p.targets);
|
||||
|
||||
try {
|
||||
const { nx }: PackageJson = readJsonFile(
|
||||
join(projectRoot, 'package.json')
|
||||
);
|
||||
if (nx?.tags) {
|
||||
p.tags = [...(p.tags || []), ...nx.tags];
|
||||
}
|
||||
if (nx?.implicitDependencies) {
|
||||
p.implicitDependencies = [
|
||||
...(p.implicitDependencies || []),
|
||||
...nx.implicitDependencies,
|
||||
];
|
||||
}
|
||||
if (nx?.namedInputs) {
|
||||
p.namedInputs = { ...(p.namedInputs || {}), ...nx.namedInputs };
|
||||
}
|
||||
} catch {
|
||||
// ignore json parser errors
|
||||
}
|
||||
}
|
||||
|
||||
p.implicitDependencies = normalizeImplicitDependencies(
|
||||
key,
|
||||
@@ -134,9 +100,8 @@ export function normalizeProjectTargets(
|
||||
// We need to know the executor for use in readTargetDefaultsForTarget,
|
||||
// but we haven't resolved the `command` syntactic sugar yet.
|
||||
const executor =
|
||||
targets[target].executor ?? targets[target].command
|
||||
? 'nx:run-commands'
|
||||
: null;
|
||||
targets[target].executor ??
|
||||
(targets[target].command ? 'nx:run-commands' : null);
|
||||
|
||||
// Allows things like { targetDefaults: { build: { command: tsc } } }
|
||||
const defaults = resolveCommandSyntacticSugar(
|
||||
|
||||
@@ -23,10 +23,7 @@ import {
|
||||
import { readJsonFile } from '../utils/fileutils';
|
||||
import { NxJsonConfiguration } from '../config/nx-json';
|
||||
import { ProjectGraphBuilder } from './project-graph-builder';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../config/workspace-json-project-json';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
import { readNxJson } from '../config/configuration';
|
||||
import { existsSync } from 'fs';
|
||||
import { PackageJson } from '../utils/package-json';
|
||||
@@ -49,7 +46,7 @@ export function getProjectFileMap(): {
|
||||
}
|
||||
|
||||
export async function buildProjectGraphUsingProjectFileMap(
|
||||
projectsConfigurations: ProjectsConfigurations,
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>,
|
||||
projectFileMap: ProjectFileMap,
|
||||
allWorkspaceFiles: FileData[],
|
||||
@@ -64,7 +61,7 @@ export async function buildProjectGraphUsingProjectFileMap(
|
||||
|
||||
const nxJson = readNxJson();
|
||||
const projectGraphVersion = '6.0';
|
||||
assertWorkspaceValidity(projectsConfigurations, nxJson);
|
||||
assertWorkspaceValidity(projects, nxJson);
|
||||
const packageJsonDeps = readCombinedDeps();
|
||||
const rootTsConfig = readRootTsConfig();
|
||||
|
||||
@@ -75,7 +72,7 @@ export async function buildProjectGraphUsingProjectFileMap(
|
||||
!shouldRecomputeWholeGraph(
|
||||
fileMap,
|
||||
packageJsonDeps,
|
||||
projectsConfigurations,
|
||||
projects,
|
||||
nxJson,
|
||||
rootTsConfig
|
||||
);
|
||||
@@ -89,7 +86,7 @@ export async function buildProjectGraphUsingProjectFileMap(
|
||||
}
|
||||
|
||||
const context = createContext(
|
||||
projectsConfigurations,
|
||||
projects,
|
||||
nxJson,
|
||||
projectFileMap,
|
||||
filesToProcess
|
||||
@@ -185,27 +182,27 @@ async function buildProjectGraphUsingContext(
|
||||
}
|
||||
|
||||
function createContext(
|
||||
projectsConfigurations: ProjectsConfigurations,
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
nxJson: NxJsonConfiguration,
|
||||
fileMap: ProjectFileMap,
|
||||
filesToProcess: ProjectFileMap
|
||||
): ProjectGraphProcessorContext {
|
||||
const projects = Object.keys(projectsConfigurations.projects).reduce(
|
||||
(map, projectName) => {
|
||||
map[projectName] = {
|
||||
...projectsConfigurations.projects[projectName],
|
||||
};
|
||||
return map;
|
||||
},
|
||||
{} as Record<string, ProjectConfiguration>
|
||||
);
|
||||
const clonedProjects = Object.keys(projects).reduce((map, projectName) => {
|
||||
map[projectName] = {
|
||||
...projects[projectName],
|
||||
};
|
||||
return map;
|
||||
}, {} as Record<string, ProjectConfiguration>);
|
||||
return {
|
||||
nxJsonConfiguration: nxJson,
|
||||
projectsConfigurations,
|
||||
workspace: {
|
||||
...projectsConfigurations,
|
||||
version: 2,
|
||||
projects: clonedProjects,
|
||||
...nxJson,
|
||||
projects,
|
||||
},
|
||||
projectsConfigurations: {
|
||||
version: 2,
|
||||
projects: clonedProjects,
|
||||
},
|
||||
fileMap,
|
||||
filesToProcess,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { Workspaces } from '../config/workspaces';
|
||||
import { execSync } from 'child_process';
|
||||
import { existsSync, readFileSync } from 'fs';
|
||||
import { extname, join, relative, sep } from 'path';
|
||||
@@ -15,6 +14,7 @@ import {
|
||||
} from './project-graph';
|
||||
import { toOldFormat } from '../adapter/angular-json';
|
||||
import { getIgnoreObject } from '../utils/ignore';
|
||||
import { retrieveProjectConfigurationsSync } from './utils/retrieve-workspace-files';
|
||||
|
||||
export interface Change {
|
||||
type: string;
|
||||
@@ -119,20 +119,28 @@ function defaultReadFileAtRevision(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO(v18): Remove this function
|
||||
* @deprecated To get projects use {@link retrieveProjectConfigurations} instead
|
||||
*/
|
||||
export function readWorkspaceConfig(opts: {
|
||||
format: 'angularCli' | 'nx';
|
||||
path?: string;
|
||||
}): ProjectsConfigurations {
|
||||
let configuration: ProjectsConfigurations | null = null;
|
||||
const root = opts.path || process.cwd();
|
||||
const nxJson = readNxJson(root);
|
||||
try {
|
||||
const projectGraph = readCachedProjectGraph();
|
||||
configuration = {
|
||||
...readNxJson(),
|
||||
...nxJson,
|
||||
...readProjectsConfigurationFromProjectGraph(projectGraph),
|
||||
};
|
||||
} catch {
|
||||
const ws = new Workspaces(opts.path || process.cwd());
|
||||
configuration = ws.readProjectsConfigurations();
|
||||
configuration = {
|
||||
version: 2,
|
||||
projects: retrieveProjectConfigurationsSync(root, nxJson).projectNodes,
|
||||
};
|
||||
}
|
||||
if (opts.format === 'angularCli') {
|
||||
return toOldFormat(configuration);
|
||||
@@ -155,8 +163,4 @@ export function readPackageJson(): any {
|
||||
// Original Exports
|
||||
export { FileData };
|
||||
// TODO(17): Remove these exports
|
||||
export {
|
||||
readNxJson,
|
||||
readAllWorkspaceConfiguration,
|
||||
workspaceLayout,
|
||||
} from '../config/configuration';
|
||||
export { readNxJson, workspaceLayout } from '../config/configuration';
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
ProjectFileMapCache,
|
||||
shouldRecomputeWholeGraph,
|
||||
} from './nx-deps-cache';
|
||||
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
import { NxJsonConfiguration } from '../config/nx-json';
|
||||
import { nxVersion } from '../utils/versions';
|
||||
|
||||
@@ -299,11 +299,10 @@ describe('nx deps utils', () => {
|
||||
return { ...defaults, ...p };
|
||||
}
|
||||
|
||||
function createProjectsConfiguration(p: any): ProjectsConfigurations {
|
||||
const defaults = {
|
||||
projects: { mylib: {} },
|
||||
} as any;
|
||||
return { ...defaults, ...p };
|
||||
function createProjectsConfiguration(
|
||||
p: any
|
||||
): Record<string, ProjectConfiguration> {
|
||||
return { mylib: {}, ...p };
|
||||
}
|
||||
|
||||
function createNxJson(p: Partial<NxJsonConfiguration>): NxJsonConfiguration {
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
ProjectFileMap,
|
||||
ProjectGraph,
|
||||
} from '../config/project-graph';
|
||||
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
import { projectGraphCacheDirectory } from '../utils/cache-directory';
|
||||
import {
|
||||
directoryExists,
|
||||
@@ -171,7 +171,7 @@ export function writeCache(
|
||||
export function shouldRecomputeWholeGraph(
|
||||
cache: ProjectFileMapCache,
|
||||
packageJsonDeps: Record<string, string>,
|
||||
projects: ProjectsConfigurations,
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
nxJson: NxJsonConfiguration,
|
||||
tsConfig: { compilerOptions: { paths: { [k: string]: any } } }
|
||||
): boolean {
|
||||
@@ -184,7 +184,7 @@ export function shouldRecomputeWholeGraph(
|
||||
|
||||
// we have a cached project that is no longer present
|
||||
const cachedNodes = Object.keys(cache.projectFileMap);
|
||||
if (cachedNodes.some((p) => projects.projects[p] === undefined)) {
|
||||
if (cachedNodes.some((p) => projects[p] === undefined)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,9 @@ export function readCachedProjectConfiguration(
|
||||
return node.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ProjectsConfigurations} from the {@link ProjectGraph}
|
||||
*/
|
||||
export function readProjectsConfigurationFromProjectGraph(
|
||||
projectGraph: ProjectGraph
|
||||
): ProjectsConfigurations {
|
||||
@@ -81,7 +84,7 @@ export async function buildProjectGraphWithoutDaemon() {
|
||||
const cacheEnabled = process.env.NX_CACHE_PROJECT_GRAPH !== 'false';
|
||||
return (
|
||||
await buildProjectGraphUsingProjectFileMap(
|
||||
projectConfigurations,
|
||||
projectConfigurations.projects,
|
||||
externalNodes,
|
||||
projectFileMap,
|
||||
allWorkspaceFiles,
|
||||
@@ -117,7 +120,7 @@ function handleProjectGraphError(opts: { exitOnError: boolean }, e) {
|
||||
* * It is running in the docker container.
|
||||
* * The daemon process is disabled because of the previous error when starting the daemon.
|
||||
* * `NX_DAEMON` is set to `false`.
|
||||
* * `useDaemon` is set to false in `nx.json`
|
||||
* * `useDaemonProcess` is set to false in the options of the tasks runner inside `nx.json`
|
||||
*
|
||||
* `NX_DAEMON` env variable takes precedence:
|
||||
* * If it is set to true, the daemon will always be used.
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { TargetConfiguration } from '../../config/workspace-json-project-json';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import {
|
||||
mergeProjectConfigurationIntoRootMap,
|
||||
mergeTargetConfigurations,
|
||||
readProjectConfigurationsFromRootMap,
|
||||
readTargetDefaultsForTarget,
|
||||
} from './project-configuration-utils';
|
||||
|
||||
@@ -352,3 +357,146 @@ describe('target defaults', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeProjectConfigurationIntoRootMap', () => {
|
||||
it('should merge targets from different configurations', () => {
|
||||
const rootMap = new RootMapBuilder()
|
||||
.addProject({
|
||||
root: 'libs/lib-a',
|
||||
name: 'lib-a',
|
||||
targets: {
|
||||
echo: {
|
||||
command: 'echo lib-a',
|
||||
},
|
||||
},
|
||||
})
|
||||
.getRootMap();
|
||||
mergeProjectConfigurationIntoRootMap(
|
||||
rootMap,
|
||||
{
|
||||
root: 'libs/lib-a',
|
||||
name: 'lib-a',
|
||||
targets: {
|
||||
build: {
|
||||
command: 'tsc',
|
||||
},
|
||||
},
|
||||
},
|
||||
'inferred-project-config-file.ts'
|
||||
);
|
||||
expect(rootMap.get('libs/lib-a')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"name": "lib-a",
|
||||
"root": "libs/lib-a",
|
||||
"targets": {
|
||||
"build": {
|
||||
"command": "tsc",
|
||||
},
|
||||
"echo": {
|
||||
"command": "echo lib-a",
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it("shouldn't overwrite project name, unless merging project from project.json", () => {
|
||||
const rootMap = new RootMapBuilder()
|
||||
.addProject({
|
||||
name: 'bad-name',
|
||||
root: 'libs/lib-a',
|
||||
})
|
||||
.getRootMap();
|
||||
mergeProjectConfigurationIntoRootMap(
|
||||
rootMap,
|
||||
{
|
||||
name: 'other-bad-name',
|
||||
root: 'libs/lib-a',
|
||||
},
|
||||
'libs/lib-a/package.json'
|
||||
);
|
||||
expect(rootMap.get('libs/lib-a').name).toEqual('bad-name');
|
||||
mergeProjectConfigurationIntoRootMap(
|
||||
rootMap,
|
||||
{
|
||||
name: 'lib-a',
|
||||
root: 'libs/lib-a',
|
||||
},
|
||||
'libs/lib-a/project.json'
|
||||
);
|
||||
expect(rootMap.get('libs/lib-a').name).toEqual('lib-a');
|
||||
});
|
||||
});
|
||||
|
||||
describe('readProjectsConfigurationsFromRootMap', () => {
|
||||
it('should error if multiple roots point to the same project', () => {
|
||||
const rootMap = new RootMapBuilder()
|
||||
.addProject({
|
||||
name: 'lib',
|
||||
root: 'apps/lib-a',
|
||||
})
|
||||
.addProject({
|
||||
name: 'lib',
|
||||
root: 'apps/lib-b',
|
||||
})
|
||||
.getRootMap();
|
||||
|
||||
expect(() => {
|
||||
readProjectConfigurationsFromRootMap(rootMap);
|
||||
}).toThrowErrorMatchingInlineSnapshot(`
|
||||
"The following projects are defined in multiple locations:
|
||||
- lib:
|
||||
- apps/lib-a
|
||||
- apps/lib-b
|
||||
|
||||
To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name."
|
||||
`);
|
||||
});
|
||||
|
||||
it('should read root map into standard projects configurations form', () => {
|
||||
const rootMap = new RootMapBuilder()
|
||||
.addProject({
|
||||
name: 'lib-a',
|
||||
root: 'libs/a',
|
||||
})
|
||||
.addProject({
|
||||
name: 'lib-b',
|
||||
root: 'libs/b',
|
||||
})
|
||||
.addProject({
|
||||
name: 'lib-shared-b',
|
||||
root: 'libs/shared/b',
|
||||
})
|
||||
.getRootMap();
|
||||
expect(readProjectConfigurationsFromRootMap(rootMap))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"lib-a": {
|
||||
"name": "lib-a",
|
||||
"root": "libs/a",
|
||||
},
|
||||
"lib-b": {
|
||||
"name": "lib-b",
|
||||
"root": "libs/b",
|
||||
},
|
||||
"lib-shared-b": {
|
||||
"name": "lib-shared-b",
|
||||
"root": "libs/shared/b",
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
class RootMapBuilder {
|
||||
private rootMap: Map<string, ProjectConfiguration> = new Map();
|
||||
|
||||
addProject(p: ProjectConfiguration) {
|
||||
this.rootMap.set(p.root, p);
|
||||
return this;
|
||||
}
|
||||
|
||||
getRootMap() {
|
||||
return this.rootMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,53 +8,42 @@ import {
|
||||
ProjectConfiguration,
|
||||
TargetConfiguration,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import { readJsonFile } from '../../utils/fileutils';
|
||||
import { NX_PREFIX } from '../../utils/logger';
|
||||
import { NxPluginV2 } from '../../utils/nx-plugin';
|
||||
import { workspaceRoot } from '../../utils/workspace-root';
|
||||
|
||||
import minimatch = require('minimatch');
|
||||
export function mergeProjectConfigurationIntoProjectsConfigurations(
|
||||
// projectName -> ProjectConfiguration
|
||||
existingProjects: Record<string, ProjectConfiguration>,
|
||||
// projectRoot -> projectName
|
||||
existingProjectRootMap: Map<string, string>,
|
||||
|
||||
export function mergeProjectConfigurationIntoRootMap(
|
||||
projectRootMap: Map<string, ProjectConfiguration>,
|
||||
project: ProjectConfiguration,
|
||||
// project.json is a special case, so we need to detect it.
|
||||
file: string
|
||||
): void {
|
||||
let matchingProjectName = existingProjectRootMap.get(project.root);
|
||||
const matchingProject = projectRootMap.get(project.root);
|
||||
|
||||
if (!matchingProjectName) {
|
||||
existingProjects[project.name] = project;
|
||||
existingProjectRootMap.set(project.root, project.name);
|
||||
if (!matchingProject) {
|
||||
projectRootMap.set(project.root, project);
|
||||
return;
|
||||
// There are some special cases for handling project.json - mainly
|
||||
// that it should override any name the project already has.
|
||||
} else if (
|
||||
project.name &&
|
||||
project.name !== matchingProjectName &&
|
||||
project.name !== matchingProject.name &&
|
||||
basename(file) === 'project.json'
|
||||
) {
|
||||
// Copy config to new name
|
||||
existingProjects[project.name] = existingProjects[matchingProjectName];
|
||||
// Update name in project config
|
||||
existingProjects[project.name].name = project.name;
|
||||
// Update root map to point to new name
|
||||
existingProjectRootMap[project.root] = project.name;
|
||||
// Remove entry for old name
|
||||
delete existingProjects[matchingProjectName];
|
||||
// Update name that config should be merged to
|
||||
matchingProjectName = project.name;
|
||||
// `name` inside project.json overrides any names from
|
||||
// inference plugins
|
||||
matchingProject.name = project.name;
|
||||
}
|
||||
|
||||
const matchingProject = existingProjects[matchingProjectName];
|
||||
|
||||
// This handles top level properties that are overwritten. `srcRoot`, `projectType`, or fields that Nx doesn't know about.
|
||||
// This handles top level properties that are overwritten.
|
||||
// e.g. `srcRoot`, `projectType`, or other fields that shouldn't be extended
|
||||
// Note: `name` is set specifically here to keep it from changing. The name is
|
||||
// always determined by the first inference plugin to ID a project, unless it has
|
||||
// a project.json in which case it was already updated above.
|
||||
const updatedProjectConfiguration = {
|
||||
...matchingProject,
|
||||
...project,
|
||||
name: matchingProjectName,
|
||||
name: matchingProject.name,
|
||||
};
|
||||
|
||||
// The next blocks handle properties that should be themselves merged (e.g. targets, tags, and implicit dependencies)
|
||||
@@ -83,11 +72,10 @@ export function mergeProjectConfigurationIntoProjectsConfigurations(
|
||||
};
|
||||
}
|
||||
|
||||
if (updatedProjectConfiguration.name !== matchingProject.name) {
|
||||
delete existingProjects[matchingProject.name];
|
||||
}
|
||||
existingProjects[updatedProjectConfiguration.name] =
|
||||
updatedProjectConfiguration;
|
||||
projectRootMap.set(
|
||||
updatedProjectConfiguration.root,
|
||||
updatedProjectConfiguration
|
||||
);
|
||||
}
|
||||
|
||||
export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
|
||||
@@ -99,8 +87,7 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
|
||||
projects: Record<string, ProjectConfiguration>;
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>;
|
||||
} {
|
||||
const projectRootMap: Map<string, string> = new Map();
|
||||
const projects: Record<string, ProjectConfiguration> = {};
|
||||
const projectRootMap: Map<string, ProjectConfiguration> = new Map();
|
||||
const externalNodes: Record<string, ProjectGraphExternalNode> = {};
|
||||
|
||||
// We push the nx core node builder onto the end, s.t. it overwrites any user specified behavior
|
||||
@@ -119,13 +106,12 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
|
||||
if (minimatch(file, pattern)) {
|
||||
const { projects: projectNodes, externalNodes: pluginExternalNodes } =
|
||||
configurationConstructor(file, {
|
||||
projectsConfigurations: projects,
|
||||
nxJsonConfiguration: nxJson,
|
||||
workspaceRoot: root,
|
||||
});
|
||||
for (const node in projectNodes) {
|
||||
mergeProjectConfigurationIntoProjectsConfigurations(
|
||||
projects,
|
||||
projectNodes[node].name ??= node;
|
||||
mergeProjectConfigurationIntoRootMap(
|
||||
projectRootMap,
|
||||
projectNodes[node],
|
||||
file
|
||||
@@ -136,7 +122,48 @@ export function buildProjectsConfigurationsFromProjectPathsAndPlugins(
|
||||
}
|
||||
}
|
||||
|
||||
return { projects, externalNodes };
|
||||
return {
|
||||
projects: readProjectConfigurationsFromRootMap(projectRootMap),
|
||||
externalNodes,
|
||||
};
|
||||
}
|
||||
|
||||
export function readProjectConfigurationsFromRootMap(
|
||||
projectRootMap: Map<string, ProjectConfiguration>
|
||||
) {
|
||||
const projects: Record<string, ProjectConfiguration> = {};
|
||||
// If there are projects that have the same name, that is an error.
|
||||
// This object tracks name -> (all roots of projects with that name)
|
||||
// to provide better error messaging.
|
||||
const errors: Map<string, string[]> = new Map();
|
||||
|
||||
for (const [root, configuration] of projectRootMap.entries()) {
|
||||
if (!configuration.name) {
|
||||
throw new Error(`Project at ${root} has no name provided.`);
|
||||
} else if (configuration.name in projects) {
|
||||
let rootErrors = errors.get(configuration.name) ?? [
|
||||
projects[configuration.name].root,
|
||||
];
|
||||
rootErrors.push(root);
|
||||
errors.set(configuration.name, rootErrors);
|
||||
} else {
|
||||
projects[configuration.name] = configuration;
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.size > 0) {
|
||||
throw new Error(
|
||||
[
|
||||
`The following projects are defined in multiple locations:`,
|
||||
...Array.from(errors.entries()).map(([project, roots]) =>
|
||||
[`- ${project}: `, ...roots.map((r) => ` - ${r}`)].join('\n')
|
||||
),
|
||||
'',
|
||||
"To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.",
|
||||
].join('\n')
|
||||
);
|
||||
}
|
||||
return projects;
|
||||
}
|
||||
|
||||
export function mergeTargetConfigurations(
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { performance } from 'perf_hooks';
|
||||
import { getNxRequirePaths } from '../../utils/installation-directory';
|
||||
import { readJsonFile } from '../../utils/fileutils';
|
||||
import { join } from 'path';
|
||||
import {
|
||||
ProjectConfiguration,
|
||||
ProjectsConfigurations,
|
||||
} from '../../config/workspace-json-project-json';
|
||||
import {
|
||||
mergeAngularJsonAndProjects,
|
||||
NxAngularJsonPlugin,
|
||||
NX_ANGULAR_JSON_PLUGIN_NAME,
|
||||
shouldMergeAngularProjects,
|
||||
} from '../../adapter/angular-json';
|
||||
import { NxJsonConfiguration, readNxJson } from '../../config/nx-json';
|
||||
@@ -22,6 +21,7 @@ import { buildProjectsConfigurationsFromProjectPathsAndPlugins } from './project
|
||||
import {
|
||||
loadNxPlugins,
|
||||
loadNxPluginsSync,
|
||||
NxPlugin,
|
||||
NxPluginV2,
|
||||
} from '../../utils/nx-plugin';
|
||||
|
||||
@@ -99,14 +99,71 @@ export async function retrieveProjectConfigurations(
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>;
|
||||
projectNodes: Record<string, ProjectConfiguration>;
|
||||
}> {
|
||||
const { getProjectConfigurations } =
|
||||
require('../../native') as typeof import('../../native');
|
||||
const plugins = await loadNxPlugins(
|
||||
nxJson?.plugins ?? [],
|
||||
getNxRequirePaths(workspaceRoot),
|
||||
workspaceRoot
|
||||
);
|
||||
|
||||
const globs = configurationGlobs(workspaceRoot, plugins);
|
||||
return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs);
|
||||
}
|
||||
|
||||
export async function retrieveProjectConfigurationsWithAngularProjects(
|
||||
workspaceRoot: string,
|
||||
nxJson: NxJsonConfiguration
|
||||
): Promise<{
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>;
|
||||
projectNodes: Record<string, ProjectConfiguration>;
|
||||
}> {
|
||||
const plugins = await loadNxPlugins(
|
||||
nxJson?.plugins ?? [],
|
||||
getNxRequirePaths(workspaceRoot),
|
||||
workspaceRoot
|
||||
);
|
||||
|
||||
if (
|
||||
shouldMergeAngularProjects(workspaceRoot, true) &&
|
||||
!plugins.some((p) => p.name === NX_ANGULAR_JSON_PLUGIN_NAME)
|
||||
) {
|
||||
plugins.push(NxAngularJsonPlugin);
|
||||
}
|
||||
|
||||
const globs = configurationGlobs(workspaceRoot, plugins);
|
||||
return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link retrieveProjectConfigurations} instead.
|
||||
*/
|
||||
export function retrieveProjectConfigurationsSync(
|
||||
workspaceRoot: string,
|
||||
nxJson: NxJsonConfiguration
|
||||
): {
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>;
|
||||
projectNodes: Record<string, ProjectConfiguration>;
|
||||
} {
|
||||
const plugins = loadNxPluginsSync(
|
||||
nxJson?.plugins ?? [],
|
||||
getNxRequirePaths(workspaceRoot),
|
||||
workspaceRoot
|
||||
);
|
||||
|
||||
const globs = configurationGlobs(workspaceRoot, plugins);
|
||||
return _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins, globs);
|
||||
}
|
||||
|
||||
function _retrieveProjectConfigurations(
|
||||
workspaceRoot: string,
|
||||
nxJson: NxJsonConfiguration,
|
||||
plugins: NxPluginV2[],
|
||||
globs: string[]
|
||||
): {
|
||||
externalNodes: Record<string, ProjectGraphExternalNode>;
|
||||
projectNodes: Record<string, ProjectConfiguration>;
|
||||
} {
|
||||
const { getProjectConfigurations } =
|
||||
require('../../native') as typeof import('../../native');
|
||||
return getProjectConfigurations(workspaceRoot, globs, (configs: string[]) => {
|
||||
const projectConfigurations = createProjectConfigurations(
|
||||
workspaceRoot,
|
||||
@@ -227,12 +284,6 @@ function createProjectConfigurations(
|
||||
|
||||
let projectConfigurations = projects;
|
||||
|
||||
if (shouldMergeAngularProjects(workspaceRoot, false)) {
|
||||
projectConfigurations = mergeAngularJsonAndProjects(
|
||||
projectConfigurations,
|
||||
workspaceRoot
|
||||
);
|
||||
}
|
||||
performance.mark('build-project-configs:end');
|
||||
performance.measure(
|
||||
'build-project-configs',
|
||||
|
||||
@@ -27,7 +27,7 @@ export class TaskProfilingLifeCycle implements LifeCycle {
|
||||
}
|
||||
for (let t of tasks) {
|
||||
this.timings[t.id] = {
|
||||
perfStart: performance.now(),
|
||||
perfStart: Date.now(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export class TaskProfilingLifeCycle implements LifeCycle {
|
||||
if (tr.task.endTime) {
|
||||
this.timings[tr.task.id].perfEnd = tr.task.endTime;
|
||||
} else {
|
||||
this.timings[tr.task.id].perfEnd = performance.now();
|
||||
this.timings[tr.task.id].perfEnd = Date.now();
|
||||
}
|
||||
}
|
||||
this.recordTaskCompletions(taskResults, metadata);
|
||||
|
||||
@@ -24,7 +24,6 @@ import { createTaskGraph } from './create-task-graph';
|
||||
import { findCycle, makeAcyclic } from './task-graph-utils';
|
||||
import { TargetDependencyConfig } from '../config/workspace-json-project-json';
|
||||
import { handleErrors } from '../utils/params';
|
||||
import { Workspaces } from '../config/workspaces';
|
||||
import {
|
||||
DaemonBasedTaskHasher,
|
||||
InProcessTaskHasher,
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { TasksSchedule } from './tasks-schedule';
|
||||
import { Workspaces } from '../config/workspaces';
|
||||
import { removeTasksFromTaskGraph } from './utils';
|
||||
import { Task, TaskGraph } from '../config/task-graph';
|
||||
import { DependencyType, ProjectGraph } from '../config/project-graph';
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Workspaces } from '../config/workspaces';
|
||||
|
||||
import {
|
||||
calculateReverseDeps,
|
||||
getExecutorForTask,
|
||||
@@ -10,7 +8,6 @@ import { DefaultTasksRunnerOptions } from './default-tasks-runner';
|
||||
import { TaskHasher } from '../hasher/task-hasher';
|
||||
import { Task, TaskGraph } from '../config/task-graph';
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { NxJsonConfiguration } from '../config/nx-json';
|
||||
import { hashTask } from '../hasher/hash-task';
|
||||
import { findAllProjectNodeDependencies } from '../utils/project-graph-utils';
|
||||
import { reverse } from '../project-graph/operators';
|
||||
|
||||
@@ -1,38 +1,36 @@
|
||||
import { assertWorkspaceValidity } from './assert-workspace-validity';
|
||||
|
||||
describe('assertWorkspaceValidity', () => {
|
||||
let mockWorkspaceJson: any;
|
||||
let mockProjects: any;
|
||||
|
||||
beforeEach(() => {
|
||||
mockWorkspaceJson = {
|
||||
projects: {
|
||||
app1: {},
|
||||
'app1-e2e': {},
|
||||
app2: {},
|
||||
'app2-e2e': {},
|
||||
lib1: {},
|
||||
lib2: {},
|
||||
},
|
||||
mockProjects = {
|
||||
app1: {},
|
||||
'app1-e2e': {},
|
||||
app2: {},
|
||||
'app2-e2e': {},
|
||||
lib1: {},
|
||||
lib2: {},
|
||||
};
|
||||
});
|
||||
|
||||
it('should not throw for a valid workspace', () => {
|
||||
assertWorkspaceValidity(mockWorkspaceJson, {});
|
||||
assertWorkspaceValidity(mockProjects, {});
|
||||
});
|
||||
|
||||
it('should not throw for a project-level implicit dependency with a glob', () => {
|
||||
mockWorkspaceJson.projects.app2.implicitDependencies = ['lib*'];
|
||||
mockProjects.app2.implicitDependencies = ['lib*'];
|
||||
|
||||
expect(() => {
|
||||
assertWorkspaceValidity(mockWorkspaceJson, {});
|
||||
assertWorkspaceValidity(mockProjects, {});
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw for an invalid project-level implicit dependency', () => {
|
||||
mockWorkspaceJson.projects.app2.implicitDependencies = ['invalidproj'];
|
||||
mockWorkspaceJson.projects.lib1.implicitDependencies = '*';
|
||||
mockProjects.app2.implicitDependencies = ['invalidproj'];
|
||||
mockProjects.lib1.implicitDependencies = '*';
|
||||
|
||||
expect(() => assertWorkspaceValidity(mockWorkspaceJson, {}))
|
||||
expect(() => assertWorkspaceValidity(mockProjects, {}))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"Configuration Error
|
||||
The following implicitDependencies should be an array of strings:
|
||||
@@ -45,10 +43,10 @@ describe('assertWorkspaceValidity', () => {
|
||||
});
|
||||
|
||||
it('should throw for an invalid project-level implicit dependency with glob', () => {
|
||||
mockWorkspaceJson.projects.app2.implicitDependencies = ['invalid*'];
|
||||
mockProjects.app2.implicitDependencies = ['invalid*'];
|
||||
|
||||
try {
|
||||
assertWorkspaceValidity(mockWorkspaceJson, {});
|
||||
assertWorkspaceValidity(mockProjects, {});
|
||||
fail('should not reach');
|
||||
} catch (e) {
|
||||
expect(e.message).toContain(
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { ProjectsConfigurations } from '../config/workspace-json-project-json';
|
||||
import { ProjectConfiguration } from '../config/workspace-json-project-json';
|
||||
import { NxJsonConfiguration } from '../config/nx-json';
|
||||
import { findMatchingProjects } from './find-matching-projects';
|
||||
import { output } from './output';
|
||||
import { ProjectGraphProjectNode } from '../config/project-graph';
|
||||
|
||||
export function assertWorkspaceValidity(
|
||||
projectsConfigurations: ProjectsConfigurations,
|
||||
projects: Record<string, ProjectConfiguration>,
|
||||
nxJson: NxJsonConfiguration
|
||||
) {
|
||||
const projectNames = Object.keys(projectsConfigurations.projects);
|
||||
const projectNames = Object.keys(projects);
|
||||
const projectGraphNodes = projectNames.reduce((graph, project) => {
|
||||
const projectConfiguration = projectsConfigurations.projects[project];
|
||||
const projectConfiguration = projects[project];
|
||||
graph[project] = {
|
||||
name: project,
|
||||
type: projectConfiguration.projectType === 'library' ? 'lib' : 'app', // missing fallback to `e2e`
|
||||
@@ -21,10 +21,6 @@ export function assertWorkspaceValidity(
|
||||
return graph;
|
||||
}, {} as Record<string, ProjectGraphProjectNode>);
|
||||
|
||||
const projects = {
|
||||
...projectsConfigurations.projects,
|
||||
};
|
||||
|
||||
const invalidImplicitDependencies = new Map<string, string[]>();
|
||||
|
||||
if (nxJson.implicitDependencies) {
|
||||
@@ -110,7 +106,7 @@ function detectAndSetInvalidProjectGlobValues(
|
||||
map: Map<string, string[]>,
|
||||
sourceName: string,
|
||||
desiredImplicitDeps: string[],
|
||||
projectConfigurations: ProjectsConfigurations['projects'],
|
||||
projectConfigurations: Record<string, ProjectConfiguration>,
|
||||
projects: Record<string, ProjectGraphProjectNode>
|
||||
) {
|
||||
const invalidProjectsOrGlobs = desiredImplicitDeps.filter((implicit) => {
|
||||
|
||||
@@ -37,12 +37,15 @@ import { retrieveProjectConfigurationsWithoutPluginInference } from '../project-
|
||||
import { NxPluginV1 } from './nx-plugin.deprecated';
|
||||
import { ProjectGraphDependencyWithFile } from '../project-graph/project-graph-builder';
|
||||
import { combineGlobPatterns } from './globs';
|
||||
import {
|
||||
NxAngularJsonPlugin,
|
||||
shouldMergeAngularProjects,
|
||||
} from '../adapter/angular-json';
|
||||
|
||||
/**
|
||||
* Context for {@link CreateNodesFunction}
|
||||
*/
|
||||
export interface CreateNodesContext {
|
||||
readonly projectsConfigurations: Record<string, ProjectConfiguration>;
|
||||
readonly nxJsonConfiguration: NxJsonConfiguration;
|
||||
readonly workspaceRoot: string;
|
||||
}
|
||||
@@ -253,6 +256,10 @@ export async function loadNxPlugins(
|
||||
jsPlugin.name = 'nx-js-graph-plugin';
|
||||
result.push(jsPlugin as NxPlugin);
|
||||
|
||||
if (shouldMergeAngularProjects(root, false)) {
|
||||
result.push(NxAngularJsonPlugin);
|
||||
}
|
||||
|
||||
plugins ??= [];
|
||||
for (const plugin of plugins) {
|
||||
result.push(await loadNxPluginAsync(plugin, paths, root));
|
||||
@@ -262,6 +269,9 @@ export async function loadNxPlugins(
|
||||
}
|
||||
|
||||
function ensurePluginIsV2(plugin: NxPlugin): NxPluginV2 {
|
||||
if (isNxPluginV2(plugin)) {
|
||||
return plugin;
|
||||
}
|
||||
if (isNxPluginV1(plugin) && plugin.projectFilePatterns) {
|
||||
return {
|
||||
...plugin,
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
PackageJson,
|
||||
PackageJsonTargetConfiguration,
|
||||
readModulePackageJson,
|
||||
readTargetsFromPackageJson,
|
||||
} from './package-json';
|
||||
|
||||
describe('buildTargetFromScript', () => {
|
||||
@@ -44,6 +45,76 @@ describe('buildTargetFromScript', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('readTargetsFromPackageJson', () => {
|
||||
const packageJson: PackageJson = {
|
||||
name: 'my-app',
|
||||
version: '0.0.0',
|
||||
scripts: {
|
||||
build: 'echo 1',
|
||||
},
|
||||
};
|
||||
|
||||
const packageJsonBuildTarget = {
|
||||
executor: 'nx:run-script',
|
||||
options: {
|
||||
script: 'build',
|
||||
},
|
||||
};
|
||||
|
||||
it('should read targets from project.json and package.json', () => {
|
||||
const result = readTargetsFromPackageJson(packageJson);
|
||||
expect(result).toEqual({
|
||||
build: {
|
||||
executor: 'nx:run-script',
|
||||
options: {
|
||||
script: 'build',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should contain extended options from nx property in package.json', () => {
|
||||
const result = readTargetsFromPackageJson({
|
||||
name: 'my-other-app',
|
||||
version: '',
|
||||
scripts: {
|
||||
build: 'echo 1',
|
||||
},
|
||||
nx: {
|
||||
targets: {
|
||||
build: {
|
||||
outputs: ['custom'],
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(result).toEqual({
|
||||
build: { ...packageJsonBuildTarget, outputs: ['custom'] },
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore scripts that are not in includedScripts', () => {
|
||||
const result = readTargetsFromPackageJson({
|
||||
name: 'included-scripts-test',
|
||||
version: '',
|
||||
scripts: {
|
||||
test: 'echo testing',
|
||||
fail: 'exit 1',
|
||||
},
|
||||
nx: {
|
||||
includedScripts: ['test'],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
test: {
|
||||
executor: 'nx:run-script',
|
||||
options: { script: 'test' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const rootPackageJson: PackageJson = readJsonFile(
|
||||
join(workspaceRoot, 'package.json')
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user