Skip to content

Commit e4f7e56

Browse files
authored
fix(core): handle nx config in package.json in move generator (#30270)
## Current Behavior When the Nx configuration is in `package.json#nx` and not in `project.json`, the move generator creates a `project.json` file in the new destination. ## Expected Behavior When the Nx configuration is in `package.json#nx` and not in `project.json`, the move generator should not create a `project.json` file in the new destination and should update the `nx` entry in the `package.json` file. ## Related Issue(s) Fixes #
1 parent e8acab6 commit e4f7e56

File tree

4 files changed

+106
-72
lines changed

4 files changed

+106
-72
lines changed

packages/workspace/src/generators/move/lib/create-project-configuration-in-new-destination.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
joinPathFragments,
44
ProjectConfiguration,
55
Tree,
6+
updateProjectConfiguration,
67
} from '@nx/devkit';
78
import { NormalizedSchema } from '../schema';
89

@@ -81,6 +82,11 @@ export function createProjectConfigurationInNewDestination(
8182
);
8283
}
8384

84-
// Create a new project with the root replaced
85-
addProjectConfiguration(tree, schema.newProjectName, newProject);
85+
if (schema.isNxConfiguredInPackageJson) {
86+
// Update the existing project configuration in the package.json
87+
updateProjectConfiguration(tree, schema.newProjectName, newProject);
88+
} else {
89+
// Create a new project with the root replaced
90+
addProjectConfiguration(tree, schema.newProjectName, newProject);
91+
}
8692
}

packages/workspace/src/generators/move/lib/normalize-schema.ts

Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,17 @@ export async function normalizeSchema(
2020
projectConfiguration
2121
);
2222

23+
const isNxConfiguredInPackageJson = !tree.exists(
24+
joinPathFragments(projectConfiguration.root, 'project.json')
25+
);
26+
2327
return {
2428
...schema,
2529
destination: normalizePathSlashes(schema.destination),
2630
importPath,
2731
newProjectName,
2832
relativeToRootDestination: destination,
33+
isNxConfiguredInPackageJson,
2934
};
3035
}
3136

@@ -41,13 +46,45 @@ async function determineProjectNameAndRootOptions(
4146
projectConfiguration: ProjectConfiguration
4247
): Promise<ProjectNameAndRootOptions> {
4348
validateName(tree, options.newProjectName, projectConfiguration);
44-
const projectNameAndRootOptions = getProjectNameAndRootOptions(
45-
tree,
46-
options,
47-
projectConfiguration
48-
);
4949

50-
return projectNameAndRootOptions;
50+
let destination = normalizePathSlashes(options.destination);
51+
52+
if (
53+
options.newProjectName &&
54+
options.newProjectName.includes('/') &&
55+
!options.newProjectName.startsWith('@')
56+
) {
57+
throw new Error(
58+
`You can't specify a new project name with a directory path (${options.newProjectName}). ` +
59+
`Please provide a valid name without path segments and the full destination with the "--destination" option.`
60+
);
61+
}
62+
63+
const newProjectName = options.newProjectName ?? options.projectName;
64+
65+
if (projectConfiguration.projectType !== 'library') {
66+
return { destination, newProjectName };
67+
}
68+
69+
let importPath = options.importPath;
70+
if (importPath) {
71+
return { destination, newProjectName, importPath };
72+
}
73+
74+
if (options.newProjectName?.startsWith('@')) {
75+
// keep the existing import path if the name didn't change
76+
importPath =
77+
options.newProjectName && options.projectName !== options.newProjectName
78+
? newProjectName
79+
: undefined;
80+
} else if (options.newProjectName) {
81+
const npmScope = getNpmScope(tree);
82+
importPath = npmScope
83+
? `${npmScope === '@' ? '' : '@'}${npmScope}/${newProjectName}`
84+
: newProjectName;
85+
}
86+
87+
return { destination, newProjectName, importPath };
5188
}
5289

5390
function validateName(
@@ -100,63 +137,3 @@ function validateName(
100137
}
101138
}
102139
}
103-
104-
function getProjectNameAndRootOptions(
105-
tree: Tree,
106-
options: Schema,
107-
projectConfiguration: ProjectConfiguration
108-
): ProjectNameAndRootOptions {
109-
let destination = normalizePathSlashes(options.destination);
110-
111-
if (
112-
options.newProjectName &&
113-
options.newProjectName.includes('/') &&
114-
!options.newProjectName.startsWith('@')
115-
) {
116-
throw new Error(
117-
`You can't specify a new project name with a directory path (${options.newProjectName}). ` +
118-
`Please provide a valid name without path segments and the full destination with the "--destination" option.`
119-
);
120-
}
121-
122-
const asProvidedOptions = getAsProvidedOptions(
123-
tree,
124-
{ ...options, destination },
125-
projectConfiguration
126-
);
127-
128-
return asProvidedOptions;
129-
}
130-
131-
function getAsProvidedOptions(
132-
tree: Tree,
133-
options: Schema,
134-
projectConfiguration: ProjectConfiguration
135-
): ProjectNameAndRootOptions {
136-
const newProjectName = options.newProjectName ?? options.projectName;
137-
const destination = options.destination;
138-
139-
if (projectConfiguration.projectType !== 'library') {
140-
return { destination, newProjectName };
141-
}
142-
143-
let importPath = options.importPath;
144-
if (importPath) {
145-
return { destination, newProjectName, importPath };
146-
}
147-
148-
if (options.newProjectName?.startsWith('@')) {
149-
// keep the existing import path if the name didn't change
150-
importPath =
151-
options.newProjectName && options.projectName !== options.newProjectName
152-
? newProjectName
153-
: undefined;
154-
} else if (options.newProjectName) {
155-
const npmScope = getNpmScope(tree);
156-
importPath = npmScope
157-
? `${npmScope === '@' ? '' : '@'}${npmScope}/${newProjectName}`
158-
: newProjectName;
159-
}
160-
161-
return { destination, newProjectName, importPath };
162-
}

packages/workspace/src/generators/move/move.spec.ts

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,10 @@ import {
44
readJson,
55
readProjectConfiguration,
66
Tree,
7-
updateJson,
87
updateProjectConfiguration,
98
} from '@nx/devkit';
109
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
1110
import { moveGenerator } from './move';
12-
// nx-ignore-next-line
13-
const { applicationGenerator } = require('@nx/react');
1411

1512
// nx-ignore-next-line
1613
const { libraryGenerator } = require('@nx/js');
@@ -72,8 +69,9 @@ describe('move', () => {
7269
destination: 'shared/two',
7370
});
7471

72+
// check that the project.json file is present
73+
expect(tree.exists('shared/two/project.json')).toBeTruthy();
7574
const myLibNewConfig = readProjectConfiguration(tree, 'two');
76-
7775
expect(myLibNewConfig.targets.custom.options.buildTarget).toEqual(
7876
'two:build:production'
7977
);
@@ -83,6 +81,8 @@ describe('move', () => {
8381
expect(myLibNewConfig.targets.custom.options.irrelevantTarget).toEqual(
8482
'my-lib:build:production'
8583
);
84+
// check that the package.json does not have nx config
85+
expect(readJson(tree, 'shared/two/package.json').nx).toBeUndefined();
8686
});
8787

8888
it('should update jest config when moving up directories', async () => {
@@ -145,4 +145,54 @@ describe('move', () => {
145145

146146
expect(tree.exists('tsconfig.base.json')).toBeFalsy();
147147
});
148+
149+
it('should correctly update the nx configuration when it is located in the package.json file', async () => {
150+
await libraryGenerator(tree, {
151+
directory: 'libs/lib1',
152+
useProjectJson: false,
153+
skipFormat: true,
154+
});
155+
updateProjectConfiguration(tree, 'lib1', {
156+
root: 'libs/lib1',
157+
targets: {
158+
foo: {
159+
command: 'echo "foo"',
160+
options: {
161+
cwd: 'libs/lib1',
162+
},
163+
},
164+
},
165+
});
166+
167+
await moveGenerator(tree, {
168+
projectName: 'lib1',
169+
destination: 'packages/lib1',
170+
updateImportPath: true,
171+
skipFormat: true,
172+
});
173+
174+
// check that the nx config in the package.json is correct
175+
const packageJson = readJson(tree, 'packages/lib1/package.json');
176+
expect(packageJson.nx).toMatchInlineSnapshot(`
177+
{
178+
"name": "lib1",
179+
"projectType": "library",
180+
"sourceRoot": "packages/lib1/src",
181+
"targets": {
182+
"foo": {
183+
"command": "echo "foo"",
184+
"options": {
185+
"cwd": "packages/lib1",
186+
},
187+
},
188+
},
189+
}
190+
`);
191+
// check that we read the project configuration with the updated paths from the package.json
192+
const myLibNewConfig = readProjectConfiguration(tree, 'lib1');
193+
expect(myLibNewConfig.sourceRoot).toEqual('packages/lib1/src');
194+
expect(myLibNewConfig.targets.foo.options.cwd).toEqual('packages/lib1');
195+
// check that the project.json file is not present
196+
expect(tree.exists('packages/lib1/project.json')).toBeFalsy();
197+
});
148198
});

packages/workspace/src/generators/move/schema.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ export interface Schema {
99

1010
export interface NormalizedSchema extends Schema {
1111
relativeToRootDestination: string;
12+
isNxConfiguredInPackageJson?: boolean;
1213
}

0 commit comments

Comments
 (0)