@nx/workspace 20.5.0 → 20.6.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/workspace",
3
- "version": "20.5.0",
3
+ "version": "20.6.0-beta.1",
4
4
  "private": false,
5
5
  "description": "The Workspace plugin contains executors and generators that are useful for any Nx workspace. It should be present in every Nx workspace and other plugins build on it.",
6
6
  "repository": {
@@ -38,12 +38,14 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@nx/devkit": "20.5.0",
41
+ "@nx/devkit": "20.6.0-beta.1",
42
+ "@zkochan/js-yaml": "0.0.7",
42
43
  "chalk": "^4.1.0",
43
44
  "enquirer": "~2.3.6",
45
+ "picomatch": "4.0.2",
44
46
  "tslib": "^2.3.0",
45
47
  "yargs-parser": "21.1.1",
46
- "nx": "20.5.0"
48
+ "nx": "20.6.0-beta.1"
47
49
  },
48
50
  "publishConfig": {
49
51
  "access": "public"
@@ -1,4 +1,4 @@
1
- import { Tree } from '@nx/devkit';
1
+ import { type GeneratorCallback, type Tree } from '@nx/devkit';
2
2
  import { Schema } from './schema';
3
- export declare function moveGenerator(tree: Tree, rawSchema: Schema): Promise<void>;
3
+ export declare function moveGenerator(tree: Tree, rawSchema: Schema): Promise<GeneratorCallback>;
4
4
  export default moveGenerator;
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.moveGenerator = moveGenerator;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const package_manager_workspaces_1 = require("../../utilities/package-manager-workspaces");
6
+ const ts_solution_setup_1 = require("../../utilities/typescript/ts-solution-setup");
5
7
  const check_destination_1 = require("./lib/check-destination");
6
8
  const create_project_configuration_in_new_destination_1 = require("./lib/create-project-configuration-in-new-destination");
9
+ const extract_base_configs_1 = require("./lib/extract-base-configs");
7
10
  const move_project_files_1 = require("./lib/move-project-files");
8
11
  const normalize_schema_1 = require("./lib/normalize-schema");
9
12
  const run_angular_plugin_1 = require("./lib/run-angular-plugin");
@@ -18,9 +21,9 @@ const update_package_json_1 = require("./lib/update-package-json");
18
21
  const update_project_root_files_1 = require("./lib/update-project-root-files");
19
22
  const update_readme_1 = require("./lib/update-readme");
20
23
  const update_storybook_config_1 = require("./lib/update-storybook-config");
21
- const extract_base_configs_1 = require("./lib/extract-base-configs");
22
24
  async function moveGenerator(tree, rawSchema) {
23
25
  let projectConfig = (0, devkit_1.readProjectConfiguration)(tree, rawSchema.projectName);
26
+ const wasIncludedInWorkspaces = (0, package_manager_workspaces_1.isProjectIncludedInPackageManagerWorkspaces)(tree, projectConfig.root);
24
27
  const schema = await (0, normalize_schema_1.normalizeSchema)(tree, rawSchema, projectConfig);
25
28
  (0, check_destination_1.checkDestination)(tree, schema, rawSchema.destination);
26
29
  if (projectConfig.root === '.') {
@@ -48,8 +51,23 @@ async function moveGenerator(tree, rawSchema) {
48
51
  (0, extract_base_configs_1.maybeMigrateEslintConfigIfRootProject)(tree, projectConfig);
49
52
  }
50
53
  await (0, run_angular_plugin_1.runAngularPlugin)(tree, schema);
54
+ let task;
55
+ if (wasIncludedInWorkspaces) {
56
+ // check if the new destination is included in the package manager workspaces
57
+ const isIncludedInWorkspaces = (0, package_manager_workspaces_1.isProjectIncludedInPackageManagerWorkspaces)(tree, schema.destination);
58
+ if (!isIncludedInWorkspaces) {
59
+ // the new destination is not included in the package manager workspaces
60
+ // so we need to add it and run a package install to ensure the symlink
61
+ // is created
62
+ await (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(tree, schema.destination);
63
+ task = () => (0, devkit_1.installPackagesTask)(tree, true);
64
+ }
65
+ }
51
66
  if (!schema.skipFormat) {
52
67
  await (0, devkit_1.formatFiles)(tree);
53
68
  }
69
+ if (task) {
70
+ return task;
71
+ }
54
72
  }
55
73
  exports.default = moveGenerator;
@@ -70,6 +70,9 @@ function generatePreset(host, opts) {
70
70
  : null,
71
71
  parsedArgs.interactive ? '--interactive=true' : '--interactive=false',
72
72
  opts.routing !== undefined ? `--routing=${opts.routing}` : null,
73
+ opts.useReactRouter !== undefined
74
+ ? `--useReactRouter=${opts.useReactRouter}`
75
+ : null,
73
76
  opts.unitTestRunner !== undefined
74
77
  ? `--unitTestRunner=${opts.unitTestRunner}`
75
78
  : null,
@@ -81,7 +84,7 @@ function generatePreset(host, opts) {
81
84
  opts.prefix !== undefined ? `--prefix=${opts.prefix}` : null,
82
85
  opts.nxCloudToken ? `--nxCloudToken=${opts.nxCloudToken}` : null,
83
86
  opts.formatter ? `--formatter=${opts.formatter}` : null,
84
- opts.workspaces ? `--workspaces` : null,
87
+ opts.workspaces !== false ? `--workspaces` : `--no-workspaces`,
85
88
  ].filter((e) => !!e);
86
89
  }
87
90
  }
@@ -112,9 +115,6 @@ function getPresetDependencies({ preset, presetVersion, bundler, e2eTestRunner,
112
115
  case presets_1.Preset.NextJs:
113
116
  case presets_1.Preset.NextJsStandalone:
114
117
  return { dependencies: { '@nx/next': versions_1.nxVersion }, dev: {} };
115
- case presets_1.Preset.RemixStandalone:
116
- case presets_1.Preset.RemixMonorepo:
117
- return { dependencies: { '@nx/remix': versions_1.nxVersion }, dev: {} };
118
118
  case presets_1.Preset.VueMonorepo:
119
119
  case presets_1.Preset.VueStandalone:
120
120
  return {
@@ -52,16 +52,6 @@ const presetToPluginMap = {
52
52
  generateLibCmd: '@nx/react',
53
53
  learnMoreLink: 'https://nx.dev/nx-api/next?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects',
54
54
  },
55
- [presets_1.Preset.RemixMonorepo]: {
56
- generateAppCmd: '@nx/remix',
57
- generateLibCmd: '@nx/react',
58
- learnMoreLink: 'https://nx.dev/nx-api/remix?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects',
59
- },
60
- [presets_1.Preset.RemixStandalone]: {
61
- generateAppCmd: '@nx/remix',
62
- generateLibCmd: '@nx/react',
63
- learnMoreLink: 'https://nx.dev/nx-api/remix?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects',
64
- },
65
55
  [presets_1.Preset.ReactNative]: {
66
56
  generateAppCmd: '@nx/react-native',
67
57
  generateLibCmd: '@nx/react',
@@ -207,12 +197,11 @@ function createFiles(tree, options) {
207
197
  options.preset === presets_1.Preset.NuxtStandalone ||
208
198
  options.preset === presets_1.Preset.NodeStandalone ||
209
199
  options.preset === presets_1.Preset.NextJsStandalone ||
210
- options.preset === presets_1.Preset.RemixStandalone ||
211
200
  options.preset === presets_1.Preset.TsStandalone
212
201
  ? './files-root-app'
213
202
  : (options.preset === presets_1.Preset.TS &&
214
- process.env.NX_ADD_PLUGINS !== 'false' &&
215
- process.env.NX_ADD_TS_PLUGIN !== 'false') ||
203
+ options.workspaces &&
204
+ process.env.NX_ADD_PLUGINS !== 'false') ||
216
205
  options.preset === presets_1.Preset.NPM
217
206
  ? './files-package-based-repo'
218
207
  : './files-integrated-repo';
@@ -227,7 +216,7 @@ function createFiles(tree, options) {
227
216
  packageManager: options.packageManager,
228
217
  });
229
218
  }
230
- async function createReadme(tree, { name, appName, directory, preset, nxCloud }, nxCloudToken) {
219
+ async function createReadme(tree, { name, appName, directory, preset, nxCloud, workspaces }, nxCloudToken) {
231
220
  const formattedNames = (0, devkit_1.names)(name);
232
221
  // default to an empty one for custom presets
233
222
  const presetInfo = presetToPluginMap[preset] ?? {
@@ -241,8 +230,7 @@ async function createReadme(tree, { name, appName, directory, preset, nxCloud },
241
230
  formattedNames,
242
231
  isJsStandalone: preset === presets_1.Preset.TsStandalone,
243
232
  isTsPreset: preset === presets_1.Preset.TS,
244
- isUsingNewTsSolutionSetup: process.env.NX_ADD_PLUGINS !== 'false' &&
245
- process.env.NX_ADD_TS_PLUGIN !== 'false',
233
+ isUsingNewTsSolutionSetup: process.env.NX_ADD_PLUGINS !== 'false' && workspaces,
246
234
  isEmptyRepo: !appName,
247
235
  appName,
248
236
  generateAppCmd: presetInfo.generateAppCmd,
@@ -325,12 +313,11 @@ function setUpWorkspacesInPackageJson(tree, options) {
325
313
  if (options.preset === presets_1.Preset.NPM ||
326
314
  (options.preset === presets_1.Preset.TS &&
327
315
  process.env.NX_ADD_PLUGINS !== 'false' &&
328
- process.env.NX_ADD_TS_PLUGIN !== 'false') ||
316
+ options.workspaces) ||
329
317
  ((options.preset === presets_1.Preset.Expo ||
330
318
  options.preset === presets_1.Preset.NextJs ||
331
319
  options.preset === presets_1.Preset.ReactMonorepo ||
332
320
  options.preset === presets_1.Preset.ReactNative ||
333
- options.preset === presets_1.Preset.RemixMonorepo ||
334
321
  options.preset === presets_1.Preset.VueMonorepo ||
335
322
  options.preset === presets_1.Preset.Nuxt ||
336
323
  options.preset === presets_1.Preset.NodeMonorepo ||
@@ -17,6 +17,7 @@ interface Schema {
17
17
  bundler?: 'vite' | 'webpack';
18
18
  standaloneApi?: boolean;
19
19
  routing?: boolean;
20
+ useReactRouter?: boolean;
20
21
  packageManager?: PackageManager;
21
22
  unitTestRunner?: 'jest' | 'vitest' | 'none';
22
23
  e2eTestRunner?: 'cypress' | 'playwright' | 'detox' | 'jest' | 'none';
@@ -25,6 +25,11 @@
25
25
  "type": "boolean",
26
26
  "default": true
27
27
  },
28
+ "useReactRouter": {
29
+ "description": "Use React Router for routing.",
30
+ "type": "boolean",
31
+ "default": false
32
+ },
28
33
  "standaloneApi": {
29
34
  "description": "Use Standalone Components if generating an Angular application.",
30
35
  "type": "boolean",
@@ -105,7 +110,7 @@
105
110
  "workspaces": {
106
111
  "description": "Whether to use package manager workspaces.",
107
112
  "type": "boolean",
108
- "default": false
113
+ "default": true
109
114
  }
110
115
  },
111
116
  "additionalProperties": true
@@ -70,9 +70,12 @@ async function createPreset(tree, options) {
70
70
  unitTestRunner: options.unitTestRunner ??
71
71
  (options.bundler === 'vite' ? 'vitest' : 'jest'),
72
72
  addPlugin,
73
+ routing: options.routing,
74
+ useReactRouter: options.useReactRouter,
73
75
  nxCloudToken: options.nxCloudToken,
74
76
  useTsSolution: options.workspaces,
75
77
  formatter: options.formatter,
78
+ useProjectJson: !options.workspaces,
76
79
  });
77
80
  }
78
81
  else if (options.preset === presets_1.Preset.ReactStandalone) {
@@ -86,6 +89,8 @@ async function createPreset(tree, options) {
86
89
  linter: options.linter,
87
90
  rootProject: true,
88
91
  bundler,
92
+ routing: options.routing,
93
+ useReactRouter: options.useReactRouter,
89
94
  e2eTestRunner: options.e2eTestRunner ?? 'playwright',
90
95
  unitTestRunner: options.unitTestRunner ?? (bundler === 'vite' ? 'vitest' : 'jest'),
91
96
  addPlugin,
@@ -93,36 +98,6 @@ async function createPreset(tree, options) {
93
98
  formatter: options.formatter,
94
99
  });
95
100
  }
96
- else if (options.preset === presets_1.Preset.RemixMonorepo) {
97
- const { applicationGenerator: remixApplicationGenerator } = require('@nx' +
98
- '/remix/generators');
99
- return remixApplicationGenerator(tree, {
100
- name: options.name,
101
- directory: (0, path_1.join)('apps', options.name),
102
- linter: options.linter,
103
- e2eTestRunner: options.e2eTestRunner ?? 'playwright',
104
- unitTestRunner: options.unitTestRunner ?? 'vitest',
105
- addPlugin,
106
- nxCloudToken: options.nxCloudToken,
107
- useTsSolution: options.workspaces,
108
- formatter: options.formatter,
109
- });
110
- }
111
- else if (options.preset === presets_1.Preset.RemixStandalone) {
112
- const { applicationGenerator: remixApplicationGenerator } = require('@nx' +
113
- '/remix/generators');
114
- return remixApplicationGenerator(tree, {
115
- name: options.name,
116
- directory: '.',
117
- linter: options.linter,
118
- e2eTestRunner: options.e2eTestRunner ?? 'playwright',
119
- rootProject: true,
120
- unitTestRunner: options.unitTestRunner ?? 'vitest',
121
- addPlugin,
122
- nxCloudToken: options.nxCloudToken,
123
- formatter: options.formatter,
124
- });
125
- }
126
101
  else if (options.preset === presets_1.Preset.VueMonorepo) {
127
102
  const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
128
103
  '/vue');
@@ -137,6 +112,7 @@ async function createPreset(tree, options) {
137
112
  nxCloudToken: options.nxCloudToken,
138
113
  useTsSolution: options.workspaces,
139
114
  formatter: options.formatter,
115
+ useProjectJson: !options.workspaces,
140
116
  });
141
117
  }
142
118
  else if (options.preset === presets_1.Preset.VueStandalone) {
@@ -168,6 +144,7 @@ async function createPreset(tree, options) {
168
144
  nxCloudToken: options.nxCloudToken,
169
145
  useTsSolution: options.workspaces,
170
146
  formatter: options.formatter,
147
+ useProjectJson: !options.workspaces,
171
148
  });
172
149
  }
173
150
  else if (options.preset === presets_1.Preset.NuxtStandalone) {
@@ -200,6 +177,7 @@ async function createPreset(tree, options) {
200
177
  addPlugin,
201
178
  useTsSolution: options.workspaces,
202
179
  formatter: options.formatter,
180
+ useProjectJson: !options.workspaces,
203
181
  });
204
182
  }
205
183
  else if (options.preset === presets_1.Preset.NextJsStandalone) {
@@ -245,6 +223,7 @@ async function createPreset(tree, options) {
245
223
  addPlugin,
246
224
  useTsSolution: options.workspaces,
247
225
  formatter: options.formatter,
226
+ useProjectJson: !options.workspaces,
248
227
  });
249
228
  }
250
229
  else if (options.preset === presets_1.Preset.Express) {
@@ -258,6 +237,7 @@ async function createPreset(tree, options) {
258
237
  addPlugin,
259
238
  useTsSolution: options.workspaces,
260
239
  formatter: options.formatter,
240
+ useProjectJson: !options.workspaces,
261
241
  });
262
242
  }
263
243
  else if (options.preset === presets_1.Preset.ReactNative) {
@@ -274,6 +254,7 @@ async function createPreset(tree, options) {
274
254
  bundler: options.bundler ?? 'webpack',
275
255
  useTsSolution: options.workspaces,
276
256
  formatter: options.formatter,
257
+ useProjectJson: !options.workspaces,
277
258
  });
278
259
  }
279
260
  else if (options.preset === presets_1.Preset.Expo) {
@@ -288,14 +269,14 @@ async function createPreset(tree, options) {
288
269
  nxCloudToken: options.nxCloudToken,
289
270
  useTsSolution: options.workspaces,
290
271
  formatter: options.formatter,
272
+ useProjectJson: !options.workspaces,
291
273
  });
292
274
  }
293
275
  else if (options.preset === presets_1.Preset.TS) {
294
276
  const { initGenerator } = require('@nx' + '/js');
295
277
  return initGenerator(tree, {
296
278
  formatter: options.formatter,
297
- addTsPlugin: process.env.NX_ADD_PLUGINS !== 'false' &&
298
- process.env.NX_ADD_TS_PLUGIN !== 'false',
279
+ addTsPlugin: process.env.NX_ADD_PLUGINS !== 'false' && options.workspaces,
299
280
  });
300
281
  }
301
282
  else if (options.preset === presets_1.Preset.TsStandalone) {
@@ -346,6 +327,7 @@ async function createPreset(tree, options) {
346
327
  addPlugin,
347
328
  useTsSolution: options.workspaces,
348
329
  formatter: options.formatter,
330
+ useProjectJson: !options.workspaces,
349
331
  });
350
332
  }
351
333
  else {
@@ -16,6 +16,7 @@ export interface Schema {
16
16
  nextAppDir?: boolean;
17
17
  nextSrcDir?: boolean;
18
18
  routing?: boolean;
19
+ useReactRouter?: boolean;
19
20
  standaloneApi?: boolean;
20
21
  unitTestRunner?: 'jest' | 'vitest' | 'none';
21
22
  e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
@@ -25,6 +25,11 @@
25
25
  "type": "boolean",
26
26
  "default": true
27
27
  },
28
+ "useReactRouter": {
29
+ "description": "Use React Router for routing.",
30
+ "type": "boolean",
31
+ "default": false
32
+ },
28
33
  "style": {
29
34
  "description": "The file extension to be used for style files.",
30
35
  "type": "string",
@@ -122,7 +127,7 @@
122
127
  "workspaces": {
123
128
  "description": "Whether to use package manager workspaces.",
124
129
  "type": "boolean",
125
- "default": false
130
+ "default": true
126
131
  }
127
132
  },
128
133
  "required": ["preset", "name"]
@@ -8,8 +8,6 @@ export declare enum Preset {
8
8
  ReactMonorepo = "react-monorepo",
9
9
  ReactStandalone = "react-standalone",
10
10
  NextJsStandalone = "nextjs-standalone",
11
- RemixMonorepo = "remix-monorepo",
12
- RemixStandalone = "remix-standalone",
13
11
  ReactNative = "react-native",
14
12
  VueMonorepo = "vue-monorepo",
15
13
  VueStandalone = "vue-standalone",
@@ -12,8 +12,6 @@ var Preset;
12
12
  Preset["ReactMonorepo"] = "react-monorepo";
13
13
  Preset["ReactStandalone"] = "react-standalone";
14
14
  Preset["NextJsStandalone"] = "nextjs-standalone";
15
- Preset["RemixMonorepo"] = "remix-monorepo";
16
- Preset["RemixStandalone"] = "remix-standalone";
17
15
  Preset["ReactNative"] = "react-native";
18
16
  Preset["VueMonorepo"] = "vue-monorepo";
19
17
  Preset["VueStandalone"] = "vue-standalone";
@@ -0,0 +1,5 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export declare function isProjectIncludedInPackageManagerWorkspaces(tree: Tree, projectRoot: string): boolean;
3
+ export declare function getPackageManagerWorkspacesPatterns(tree: Tree): string[];
4
+ export declare function isUsingPackageManagerWorkspaces(tree: Tree): boolean;
5
+ export declare function isWorkspacesEnabled(tree: Tree): boolean;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isProjectIncludedInPackageManagerWorkspaces = isProjectIncludedInPackageManagerWorkspaces;
4
+ exports.getPackageManagerWorkspacesPatterns = getPackageManagerWorkspacesPatterns;
5
+ exports.isUsingPackageManagerWorkspaces = isUsingPackageManagerWorkspaces;
6
+ exports.isWorkspacesEnabled = isWorkspacesEnabled;
7
+ const devkit_1 = require("@nx/devkit");
8
+ const posix_1 = require("node:path/posix");
9
+ const package_json_1 = require("nx/src/plugins/package-json");
10
+ const picomatch = require("picomatch");
11
+ function isProjectIncludedInPackageManagerWorkspaces(tree, projectRoot) {
12
+ if (!isUsingPackageManagerWorkspaces(tree)) {
13
+ return false;
14
+ }
15
+ const patterns = getPackageManagerWorkspacesPatterns(tree);
16
+ return patterns.some((p) => picomatch(p)((0, posix_1.join)(projectRoot, 'package.json')));
17
+ }
18
+ function getPackageManagerWorkspacesPatterns(tree) {
19
+ return (0, package_json_1.getGlobPatternsFromPackageManagerWorkspaces)(tree.root, (path) => (0, devkit_1.readJson)(tree, path, { expectComments: true }), (path) => {
20
+ const content = tree.read(path, 'utf-8');
21
+ const { load } = require('@zkochan/js-yaml');
22
+ return load(content, { filename: path });
23
+ }, (path) => tree.exists(path));
24
+ }
25
+ function isUsingPackageManagerWorkspaces(tree) {
26
+ return isWorkspacesEnabled(tree);
27
+ }
28
+ function isWorkspacesEnabled(tree) {
29
+ const packageManager = (0, devkit_1.detectPackageManager)(tree.root);
30
+ if (packageManager === 'pnpm') {
31
+ return tree.exists('pnpm-workspace.yaml');
32
+ }
33
+ // yarn and npm both use the same 'workspaces' property in package.json
34
+ if (tree.exists('package.json')) {
35
+ const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
36
+ return !!packageJson?.workspaces;
37
+ }
38
+ return false;
39
+ }
@@ -1,2 +1,3 @@
1
1
  import { type Tree } from '@nx/devkit';
2
2
  export declare function isUsingTsSolutionSetup(tree?: Tree): boolean;
3
+ export declare function addProjectToTsSolutionWorkspace(tree: Tree, projectDir: string): Promise<void>;
@@ -1,8 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isUsingTsSolutionSetup = isUsingTsSolutionSetup;
4
+ exports.addProjectToTsSolutionWorkspace = addProjectToTsSolutionWorkspace;
4
5
  const devkit_1 = require("@nx/devkit");
6
+ const posix_1 = require("node:path/posix");
5
7
  const tree_1 = require("nx/src/generators/tree");
8
+ const package_manager_workspaces_1 = require("../package-manager-workspaces");
6
9
  function isUsingPackageManagerWorkspaces(tree) {
7
10
  return isWorkspacesEnabled(tree);
8
11
  }
@@ -55,3 +58,48 @@ function isUsingTsSolutionSetup(tree) {
55
58
  return (isUsingPackageManagerWorkspaces(tree) &&
56
59
  isWorkspaceSetupWithTsSolution(tree));
57
60
  }
61
+ async function addProjectToTsSolutionWorkspace(tree, projectDir) {
62
+ const isIncluded = (0, package_manager_workspaces_1.isProjectIncludedInPackageManagerWorkspaces)(tree, projectDir);
63
+ if (isIncluded) {
64
+ return;
65
+ }
66
+ // If dir is "libs/foo", we try to use "libs/*" but we only do it if it's
67
+ // safe to do so. So, we first check if adding that pattern doesn't result
68
+ // in extra projects being matched. If extra projects are matched, or the
69
+ // dir is just "foo" then we add it as is.
70
+ const baseDir = (0, posix_1.dirname)(projectDir);
71
+ let pattern = projectDir;
72
+ if (baseDir !== '.') {
73
+ const patterns = (0, package_manager_workspaces_1.getPackageManagerWorkspacesPatterns)(tree);
74
+ const projectsBefore = await (0, devkit_1.globAsync)(tree, patterns);
75
+ patterns.push(`${baseDir}/*/package.json`);
76
+ const projectsAfter = await (0, devkit_1.globAsync)(tree, patterns);
77
+ if (projectsBefore.length + 1 === projectsAfter.length) {
78
+ // Adding the pattern to the parent directory only results in one extra
79
+ // project being matched, which is the project we're adding. It's safe
80
+ // to add the pattern to the parent directory.
81
+ pattern = `${baseDir}/*`;
82
+ }
83
+ }
84
+ if (tree.exists('pnpm-workspace.yaml')) {
85
+ const { load, dump } = require('@zkochan/js-yaml');
86
+ const workspaceFile = tree.read('pnpm-workspace.yaml', 'utf-8');
87
+ const yamlData = load(workspaceFile) ?? {};
88
+ yamlData.packages ??= [];
89
+ if (!yamlData.packages.includes(pattern)) {
90
+ yamlData.packages.push(pattern);
91
+ tree.write('pnpm-workspace.yaml', dump(yamlData, { indent: 2, quotingType: '"', forceQuotes: true }));
92
+ }
93
+ }
94
+ else {
95
+ // Update package.json
96
+ const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
97
+ if (!packageJson.workspaces) {
98
+ packageJson.workspaces = [];
99
+ }
100
+ if (!packageJson.workspaces.includes(pattern)) {
101
+ packageJson.workspaces.push(pattern);
102
+ tree.write('package.json', JSON.stringify(packageJson, null, 2));
103
+ }
104
+ }
105
+ }