Skip to content

Commit 432a645

Browse files
authored
fix(core): handle package manager workspaces configuration in move generator (#30268)
## Current Behavior Moving a project included in the package manager workspaces setup to a new destination that's not matched by that configuration results in the project not included in the package manager workspaces setup. ## Expected Behavior Moving a project included in the package manager workspaces setup to a new destination that's not matched by that configuration should result in the new destination included in the workspaces setup. ## Related Issue(s) Fixes #
1 parent d1a7ac9 commit 432a645

File tree

28 files changed

+337
-49
lines changed

28 files changed

+337
-49
lines changed

packages/detox/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export async function detoxApplicationGeneratorInternal(
6060
);
6161

6262
if (options.isUsingTsSolutionConfig) {
63-
addProjectToTsSolutionWorkspace(host, options.e2eProjectRoot);
63+
await addProjectToTsSolutionWorkspace(host, options.e2eProjectRoot);
6464
}
6565

6666
sortPackageJsonFields(host, options.e2eProjectRoot);

packages/expo/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function expoApplicationGeneratorInternal(
6565
// If we are using the new TS solution
6666
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
6767
if (options.isTsSolutionSetup) {
68-
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
68+
await addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
6969
}
7070

7171
const lintTask = await addLinting(host, {

packages/expo/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export async function expoLibraryGeneratorInternal(
7070
}
7171

7272
if (options.isUsingTsSolutionConfig) {
73-
addProjectToTsSolutionWorkspace(host, options.projectRoot);
73+
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
7474
}
7575

7676
const initTask = await init(host, { ...options, skipFormat: true });

packages/js/src/generators/library/library.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2303,6 +2303,28 @@ describe('lib', () => {
23032303
);
23042304
});
23052305

2306+
it('should add the project root to the package manager workspaces config when a more generic pattern would match other projects that were not previously included', async () => {
2307+
tree.write(
2308+
'not-included-dir/some-other-project-not-included/package.json',
2309+
'{}'
2310+
);
2311+
2312+
await libraryGenerator(tree, {
2313+
...defaultOptions,
2314+
directory: 'not-included-dir/my-lib',
2315+
bundler: 'tsc',
2316+
unitTestRunner: 'none',
2317+
linter: 'none',
2318+
});
2319+
2320+
expect(readJson(tree, 'package.json').workspaces).toContain(
2321+
'not-included-dir/my-lib'
2322+
);
2323+
expect(readJson(tree, 'package.json').workspaces).not.toContain(
2324+
'not-included-dir/*'
2325+
);
2326+
});
2327+
23062328
it('should not add a pattern for a project that already matches an existing pattern', async () => {
23072329
updateJson(tree, 'package.json', (json) => {
23082330
json.workspaces = ['packages/**'];

packages/js/src/generators/library/library.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,6 @@ export async function libraryGeneratorInternal(
100100
);
101101
const options = await normalizeOptions(tree, schema);
102102

103-
// If we are using the new TS solution
104-
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
105-
if (options.isUsingTsSolutionConfig) {
106-
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
107-
}
108-
109103
createFiles(tree, options);
110104

111105
await configureProject(tree, options);
@@ -114,6 +108,12 @@ export async function libraryGeneratorInternal(
114108
tasks.push(addProjectDependencies(tree, options));
115109
}
116110

111+
// If we are using the new TS solution
112+
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
113+
if (options.isUsingTsSolutionConfig) {
114+
await addProjectToTsSolutionWorkspace(tree, options.projectRoot);
115+
}
116+
117117
if (options.bundler === 'rollup') {
118118
const { configurationGenerator } = ensurePackage('@nx/rollup', nxVersion);
119119
await configurationGenerator(tree, {

packages/js/src/utils/package-manager-workspaces.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ export function getProjectPackageManagerWorkspaceState(
2525
return 'no-workspaces';
2626
}
2727

28-
const patterns = getGlobPatternsFromPackageManagerWorkspaces(
28+
const patterns = getPackageManagerWorkspacesPatterns(tree);
29+
const isIncluded = patterns.some((p) =>
30+
picomatch(p)(join(projectRoot, 'package.json'))
31+
);
32+
33+
return isIncluded ? 'included' : 'excluded';
34+
}
35+
36+
export function getPackageManagerWorkspacesPatterns(tree: Tree): string[] {
37+
return getGlobPatternsFromPackageManagerWorkspaces(
2938
tree.root,
3039
(path) => readJson(tree, path, { expectComments: true }),
3140
(path) => {
@@ -35,11 +44,6 @@ export function getProjectPackageManagerWorkspaceState(
3544
},
3645
(path) => tree.exists(path)
3746
);
38-
const isIncluded = patterns.some((p) =>
39-
picomatch(p)(join(projectRoot, 'package.json'))
40-
);
41-
42-
return isIncluded ? 'included' : 'excluded';
4347
}
4448

4549
export function isUsingPackageManagerWorkspaces(tree: Tree): boolean {

packages/js/src/utils/typescript/ts-solution-setup.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
globAsync,
23
joinPathFragments,
34
offsetFromRoot,
45
output,
@@ -11,6 +12,7 @@ import {
1112
import { basename, dirname, join } from 'node:path/posix';
1213
import { FsTree } from 'nx/src/generators/tree';
1314
import {
15+
getPackageManagerWorkspacesPatterns,
1416
getProjectPackageManagerWorkspaceState,
1517
isUsingPackageManagerWorkspaces,
1618
} from '../package-manager-workspaces';
@@ -211,7 +213,7 @@ export function updateTsconfigFiles(
211213
}
212214
}
213215

214-
export function addProjectToTsSolutionWorkspace(
216+
export async function addProjectToTsSolutionWorkspace(
215217
tree: Tree,
216218
projectDir: string
217219
) {
@@ -220,11 +222,26 @@ export function addProjectToTsSolutionWorkspace(
220222
return;
221223
}
222224

223-
// If dir is "libs/foo" then use "libs/*" so we don't need so many entries in the workspace file.
224-
// If dir is nested like "libs/shared/foo" then we add "libs/shared/*".
225-
// If the dir is just "foo" then we have to add it as is.
225+
// If dir is "libs/foo", we try to use "libs/*" but we only do it if it's
226+
// safe to do so. So, we first check if adding that pattern doesn't result
227+
// in extra projects being matched. If extra projects are matched, or the
228+
// dir is just "foo" then we add it as is.
226229
const baseDir = dirname(projectDir);
227-
const pattern = baseDir === '.' ? projectDir : `${baseDir}/*`;
230+
let pattern = projectDir;
231+
if (baseDir !== '.') {
232+
const patterns = getPackageManagerWorkspacesPatterns(tree);
233+
const projectsBefore = await globAsync(tree, patterns);
234+
patterns.push(`${baseDir}/*/package.json`);
235+
const projectsAfter = await globAsync(tree, patterns);
236+
237+
if (projectsBefore.length + 1 === projectsAfter.length) {
238+
// Adding the pattern to the parent directory only results in one extra
239+
// project being matched, which is the project we're adding. It's safe
240+
// to add the pattern to the parent directory.
241+
pattern = `${baseDir}/*`;
242+
}
243+
}
244+
228245
if (tree.exists('pnpm-workspace.yaml')) {
229246
const { load, dump } = require('@zkochan/js-yaml');
230247
const workspaceFile = tree.read('pnpm-workspace.yaml', 'utf-8');

packages/next/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
7373
// If we are using the new TS solution
7474
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
7575
if (options.isTsSolutionSetup) {
76-
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
76+
await addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
7777
}
7878

7979
const e2eTask = await addE2e(host, options);

packages/next/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) {
168168
);
169169

170170
if (options.isUsingTsSolutionConfig) {
171-
addProjectToTsSolutionWorkspace(host, options.projectRoot);
171+
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
172172
}
173173

174174
sortPackageJsonFields(host, options.projectRoot);

packages/node/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
516516
// If we are using the new TS solution
517517
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
518518
if (options.isUsingTsSolutionConfig) {
519-
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
519+
await addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
520520
}
521521

522522
updateTsConfigOptions(tree, options);

packages/node/src/generators/e2e-project/e2e-project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ export async function e2eProjectGeneratorInternal(
259259
// If we are using the new TS solution
260260
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
261261
if (isUsingTsSolutionConfig) {
262-
addProjectToTsSolutionWorkspace(host, options.e2eProjectRoot);
262+
await addProjectToTsSolutionWorkspace(host, options.e2eProjectRoot);
263263
}
264264

265265
if (!options.skipFormat) {

packages/node/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
5757
// If we are using the new TS solution
5858
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
5959
if (options.isUsingTsSolutionConfig) {
60-
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
60+
await addProjectToTsSolutionWorkspace(tree, options.projectRoot);
6161
}
6262

6363
const tasks: GeneratorCallback[] = [];

packages/nuxt/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
151151
// If we are using the new TS solution
152152
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
153153
if (options.isUsingTsSolutionConfig) {
154-
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
154+
await addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
155155
}
156156

157157
tasks.push(

packages/plugin/src/generators/e2e-project/e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
258258
// If we are using the new TS solution
259259
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
260260
if (options.isTsSolutionSetup) {
261-
addProjectToTsSolutionWorkspace(host, options.projectRoot);
261+
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
262262
}
263263

264264
if (!options.skipFormat) {

packages/react-native/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export async function reactNativeApplicationGeneratorInternal(
6969
// If we are using the new TS solution
7070
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
7171
if (options.isTsSolutionSetup) {
72-
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
72+
await addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
7373
}
7474

7575
const lintTask = await addLinting(host, {

packages/react-native/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export async function reactNativeLibraryGeneratorInternal(
8888
}
8989

9090
if (options.isUsingTsSolutionConfig) {
91-
addProjectToTsSolutionWorkspace(host, options.projectRoot);
91+
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
9292
}
9393

9494
const lintTask = await addLinting(host, {

packages/react/src/generators/application/application.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,6 @@ export async function applicationGeneratorInternal(
7272

7373
const options = await normalizeOptions(tree, schema);
7474

75-
// If we are using the new TS solution
76-
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
77-
if (options.isUsingTsSolutionConfig) {
78-
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
79-
}
80-
8175
showPossibleWarnings(tree, options);
8276

8377
const initTask = await reactInitGenerator(tree, {
@@ -115,6 +109,12 @@ export async function applicationGeneratorInternal(
115109
await createApplicationFiles(tree, options);
116110
addProject(tree, options);
117111

112+
// If we are using the new TS solution
113+
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
114+
if (options.isUsingTsSolutionConfig) {
115+
await addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
116+
}
117+
118118
if (options.style === 'tailwind') {
119119
const twTask = await setupTailwindGenerator(tree, {
120120
project: options.projectName,

packages/react/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
6262
const options = await normalizeOptions(host, schema);
6363

6464
if (options.isUsingTsSolutionConfig) {
65-
addProjectToTsSolutionWorkspace(host, options.projectRoot);
65+
await addProjectToTsSolutionWorkspace(host, options.projectRoot);
6666
}
6767

6868
if (options.publishable === true && !schema.importPath) {

packages/remix/src/generators/application/application.impl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export async function remixApplicationGeneratorInternal(
8585
// If we are using the new TS solution
8686
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
8787
if (options.isUsingTsSolutionConfig) {
88-
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
88+
await addProjectToTsSolutionWorkspace(tree, options.projectRoot);
8989
}
9090

9191
if (!options.isUsingTsSolutionConfig) {

packages/remix/src/generators/library/library.impl.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export async function remixLibraryGeneratorInternal(
3030
const options = await normalizeOptions(tree, schema);
3131

3232
if (options.isUsingTsSolutionConfig) {
33-
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
33+
await addProjectToTsSolutionWorkspace(tree, options.projectRoot);
3434
}
3535

3636
const jsInitTask = await jsInitGenerator(tree, {

packages/vue/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export async function applicationGeneratorInternal(
5656
// If we are using the new TS solution
5757
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
5858
if (options.isUsingTsSolutionConfig) {
59-
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
59+
await addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
6060
}
6161

6262
const nxJson = readNxJson(tree);

packages/vue/src/generators/library/library.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
5656
// If we are using the new TS solution
5757
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
5858
if (options.isUsingTsSolutionConfig) {
59-
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
59+
await addProjectToTsSolutionWorkspace(tree, options.projectRoot);
6060
}
6161

6262
if (options.isUsingTsSolutionConfig) {

packages/web/src/generators/application/application.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
301301
const options = await normalizeOptions(host, schema);
302302

303303
if (options.isUsingTsSolutionConfig) {
304-
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
304+
await addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
305305
}
306306

307307
const tasks: GeneratorCallback[] = [];

packages/workspace/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
},
4040
"dependencies": {
4141
"@nx/devkit": "file:../devkit",
42+
"@zkochan/js-yaml": "0.0.7",
4243
"chalk": "^4.1.0",
4344
"enquirer": "~2.3.6",
45+
"picomatch": "4.0.2",
4446
"tslib": "^2.3.0",
4547
"yargs-parser": "21.1.1"
4648
},

0 commit comments

Comments
 (0)