nx 16.5.0 → 16.6.0-beta.0

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",
3
- "version": "16.5.0",
3
+ "version": "16.6.0-beta.0",
4
4
  "private": false,
5
5
  "description": "The core Nx plugin contains the core functionality of Nx like the project graph, nx commands and task orchestration.",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "homepage": "https://nx.dev",
34
34
  "dependencies": {
35
- "@nrwl/tao": "16.5.0",
35
+ "@nrwl/tao": "16.6.0-beta.0",
36
36
  "@parcel/watcher": "2.0.4",
37
37
  "@yarnpkg/lockfile": "^1.1.0",
38
38
  "@yarnpkg/parsers": "3.0.0-rc.46",
@@ -80,16 +80,16 @@
80
80
  }
81
81
  },
82
82
  "optionalDependencies": {
83
- "@nx/nx-darwin-arm64": "16.5.0",
84
- "@nx/nx-darwin-x64": "16.5.0",
85
- "@nx/nx-freebsd-x64": "16.5.0",
86
- "@nx/nx-linux-arm-gnueabihf": "16.5.0",
87
- "@nx/nx-linux-arm64-gnu": "16.5.0",
88
- "@nx/nx-linux-arm64-musl": "16.5.0",
89
- "@nx/nx-linux-x64-gnu": "16.5.0",
90
- "@nx/nx-linux-x64-musl": "16.5.0",
91
- "@nx/nx-win32-arm64-msvc": "16.5.0",
92
- "@nx/nx-win32-x64-msvc": "16.5.0"
83
+ "@nx/nx-darwin-arm64": "16.6.0-beta.0",
84
+ "@nx/nx-darwin-x64": "16.6.0-beta.0",
85
+ "@nx/nx-freebsd-x64": "16.6.0-beta.0",
86
+ "@nx/nx-linux-arm-gnueabihf": "16.6.0-beta.0",
87
+ "@nx/nx-linux-arm64-gnu": "16.6.0-beta.0",
88
+ "@nx/nx-linux-arm64-musl": "16.6.0-beta.0",
89
+ "@nx/nx-linux-x64-gnu": "16.6.0-beta.0",
90
+ "@nx/nx-linux-x64-musl": "16.6.0-beta.0",
91
+ "@nx/nx-win32-arm64-msvc": "16.6.0-beta.0",
92
+ "@nx/nx-win32-x64-msvc": "16.6.0-beta.0"
93
93
  },
94
94
  "nx-migrations": {
95
95
  "migrations": "./migrations.json",
@@ -175,5 +175,5 @@
175
175
  },
176
176
  "main": "./bin/nx.js",
177
177
  "types": "./bin/nx.d.ts",
178
- "gitHead": "eaebcc34f92db2200dab0bde2e2e1dde107a47bf"
178
+ "gitHead": "5a7ffb93c9e84bffbf52f6ae9c6c1e3b8edb9d35"
179
179
  }
@@ -73,7 +73,7 @@ export declare function inferProjectFromNonStandardFile(file: string): ProjectCo
73
73
  name: string;
74
74
  };
75
75
  export declare function buildProjectsConfigurationsFromProjectPaths(nxJson: NxJsonConfiguration, projectFiles: string[], // making this parameter allows devkit to pick up newly created projects
76
- readJson?: <T extends Object>(string: any) => T): ProjectsConfigurations;
76
+ readJson?: <T extends Object>(string: any) => T): Record<string, ProjectConfiguration>;
77
77
  export declare function mergeTargetConfigurations(projectConfiguration: ProjectConfiguration, target: string, targetDefaults: TargetDefaults[string]): TargetConfiguration;
78
78
  export declare function readTargetDefaultsForTarget(targetName: string, targetDefaults: TargetDefaults, executor?: string): TargetDefaults[string];
79
79
  export declare function renamePropertyWithStableKeys(obj: any, from: string, to: string): void;
@@ -58,13 +58,16 @@ class Workspaces {
58
58
  return this.cachedProjectsConfig;
59
59
  }
60
60
  const nxJson = this.readNxJson();
61
- const projectsConfigurations = buildProjectsConfigurationsFromProjectPaths(nxJson, globForProjectFiles(this.root, (opts === null || opts === void 0 ? void 0 : opts._ignorePluginInference)
61
+ let projectsConfigurations = buildProjectsConfigurationsFromProjectPaths(nxJson, globForProjectFiles(this.root, (opts === null || opts === void 0 ? void 0 : opts._ignorePluginInference)
62
62
  ? []
63
63
  : getGlobPatternsFromPlugins(nxJson, (0, installation_directory_1.getNxRequirePaths)(this.root), this.root), nxJson), (path) => (0, fileutils_1.readJsonFile)((0, path_1.join)(this.root, path)));
64
64
  if ((0, angular_json_1.shouldMergeAngularProjects)(this.root, opts === null || opts === void 0 ? void 0 : opts._includeProjectsFromAngularJson)) {
65
- projectsConfigurations.projects = (0, angular_json_1.mergeAngularJsonAndProjects)(projectsConfigurations.projects, this.root);
65
+ projectsConfigurations = (0, angular_json_1.mergeAngularJsonAndProjects)(projectsConfigurations, this.root);
66
66
  }
67
- this.cachedProjectsConfig = this.mergeTargetDefaultsIntoProjectDescriptions(projectsConfigurations, nxJson);
67
+ this.cachedProjectsConfig = {
68
+ version: 2,
69
+ projects: this.mergeTargetDefaultsIntoProjectDescriptions(projectsConfigurations, nxJson),
70
+ };
68
71
  return this.cachedProjectsConfig;
69
72
  }
70
73
  /**
@@ -74,8 +77,8 @@ class Workspaces {
74
77
  const nxJson = this.readNxJson();
75
78
  return Object.assign(Object.assign({}, this.readProjectsConfigurations(opts)), nxJson);
76
79
  }
77
- mergeTargetDefaultsIntoProjectDescriptions(config, nxJson) {
78
- for (const proj of Object.values(config.projects)) {
80
+ mergeTargetDefaultsIntoProjectDescriptions(projects, nxJson) {
81
+ for (const proj of Object.values(projects)) {
79
82
  if (proj.targets) {
80
83
  for (const targetName of Object.keys(proj.targets)) {
81
84
  const projectTargetDefinition = proj.targets[targetName];
@@ -86,7 +89,7 @@ class Workspaces {
86
89
  }
87
90
  }
88
91
  }
89
- return config;
92
+ return projects;
90
93
  }
91
94
  isNxExecutor(nodeModule, executor) {
92
95
  return !this.readExecutor(nodeModule, executor).isNgCompat;
@@ -565,10 +568,7 @@ readJson = (string) => (0, fileutils_1.readJsonFile)(string) // making this an a
565
568
  }
566
569
  }
567
570
  }
568
- return {
569
- version: 2,
570
- projects: projects,
571
- };
571
+ return projects;
572
572
  }
573
573
  exports.buildProjectsConfigurationsFromProjectPaths = buildProjectsConfigurationsFromProjectPaths;
574
574
  function mergeTargetConfigurations(projectConfiguration, target, targetDefaults) {
@@ -119,7 +119,7 @@ function readAndCombineAllProjectConfigurations(tree) {
119
119
  const createdFiles = findCreatedProjectFiles(tree);
120
120
  const deletedFiles = findDeletedProjectFiles(tree);
121
121
  const projectFiles = [...globbedFiles, ...createdFiles].filter((r) => deletedFiles.indexOf(r) === -1);
122
- return (0, workspaces_1.buildProjectsConfigurationsFromProjectPaths)(nxJson, projectFiles, (file) => (0, json_1.readJson)(tree, file)).projects;
122
+ return (0, workspaces_1.buildProjectsConfigurationsFromProjectPaths)(nxJson, projectFiles, (file) => (0, json_1.readJson)(tree, file));
123
123
  }
124
124
  /**
125
125
  * Used to ensure that projects created during
@@ -188,7 +188,7 @@ class TaskHasherImpl {
188
188
  return yield this.hashNamedInputForDependencies(d.target, task, input.input || 'default', visited);
189
189
  }
190
190
  else {
191
- const hash = this.hashExternalDependency(d.target);
191
+ const hash = this.hashExternalDependency(d.source, d.target);
192
192
  return {
193
193
  value: hash,
194
194
  details: {
@@ -239,13 +239,16 @@ class TaskHasherImpl {
239
239
  }
240
240
  return partialHashes;
241
241
  }
242
- hashExternalDependency(projectName, visited = new Set()) {
242
+ computeExternalDependencyIdentifier(sourceProjectName, targetProjectName) {
243
+ return `${sourceProjectName}->${targetProjectName}`;
244
+ }
245
+ hashExternalDependency(sourceProjectName, targetProjectName, visited = new Set()) {
243
246
  // try to retrieve the hash from cache
244
- if (this.externalDepsHashCache[projectName]) {
245
- return this.externalDepsHashCache[projectName];
247
+ if (this.externalDepsHashCache[targetProjectName]) {
248
+ return this.externalDepsHashCache[targetProjectName];
246
249
  }
247
- visited.add(projectName);
248
- const node = this.projectGraph.externalNodes[projectName];
250
+ visited.add(this.computeExternalDependencyIdentifier(sourceProjectName, targetProjectName));
251
+ const node = this.projectGraph.externalNodes[targetProjectName];
249
252
  let partialHash;
250
253
  if (node) {
251
254
  const partialHashes = [];
@@ -258,10 +261,10 @@ class TaskHasherImpl {
258
261
  partialHashes.push(node.data.version);
259
262
  }
260
263
  // we want to calculate the hash of the entire dependency tree
261
- if (this.projectGraph.dependencies[projectName]) {
262
- this.projectGraph.dependencies[projectName].forEach((d) => {
263
- if (!visited.has(d.target)) {
264
- partialHashes.push(this.hashExternalDependency(d.target, visited));
264
+ if (this.projectGraph.dependencies[targetProjectName]) {
265
+ this.projectGraph.dependencies[targetProjectName].forEach((d) => {
266
+ if (!visited.has(this.computeExternalDependencyIdentifier(targetProjectName, d.target))) {
267
+ partialHashes.push(this.hashExternalDependency(targetProjectName, d.target, visited));
265
268
  }
266
269
  });
267
270
  }
@@ -272,9 +275,9 @@ class TaskHasherImpl {
272
275
  // this may occur if dependency is not an npm package
273
276
  // but rather symlinked in node_modules or it's pointing to a remote git repo
274
277
  // in this case we have no information about the versioning of the given package
275
- partialHash = `__${projectName}__`;
278
+ partialHash = `__${targetProjectName}__`;
276
279
  }
277
- this.externalDepsHashCache[projectName] = partialHash;
280
+ this.externalDepsHashCache[targetProjectName] = partialHash;
278
281
  return partialHash;
279
282
  }
280
283
  hashTarget(projectName, targetName, selfInputs) {
@@ -290,7 +293,7 @@ class TaskHasherImpl {
290
293
  target.executor.startsWith(`@nx/`)) {
291
294
  const executorPackage = target.executor.split(':')[0];
292
295
  const executorNodeName = this.findExternalDependencyNodeName(executorPackage);
293
- hash = this.hashExternalDependency(executorNodeName);
296
+ hash = this.hashExternalDependency(projectName, executorNodeName);
294
297
  }
295
298
  else {
296
299
  // use command external dependencies if available to construct the hash
@@ -303,7 +306,7 @@ class TaskHasherImpl {
303
306
  const externalDependencies = input['externalDependencies'];
304
307
  for (let dep of externalDependencies) {
305
308
  dep = this.findExternalDependencyNodeName(dep);
306
- partialHashes.push(this.hashExternalDependency(dep));
309
+ partialHashes.push(this.hashExternalDependency(projectName, dep));
307
310
  }
308
311
  }
309
312
  }
@@ -37,14 +37,13 @@ export const enum WorkspaceErrors {
37
37
  Generic = 'Generic'
38
38
  }
39
39
  /** Get workspace config files based on provided globs */
40
- export function getConfigFiles(workspaceRoot: string, globs: Array<string>): Array<string>
40
+ export function getProjectConfigurations(workspaceRoot: string, globs: Array<string>, parseConfigurations: (arg0: Array<string>) => Record<string, object>): Record<string, object>
41
41
  export interface NxWorkspaceFiles {
42
42
  projectFileMap: Record<string, Array<FileData>>
43
43
  globalFiles: Array<FileData>
44
- configFiles: Array<string>
44
+ projectConfigurations: Record<string, object>
45
45
  }
46
- /** Throws exceptions */
47
- export function getWorkspaceFilesNative(workspaceRoot: string, globs: Array<string>): NxWorkspaceFiles
46
+ export function getWorkspaceFilesNative(workspaceRoot: string, globs: Array<string>, parseConfigurations: (arg0: Array<string>) => Record<string, object>): NxWorkspaceFiles
48
47
  export class Watcher {
49
48
  origin: string
50
49
  /**
@@ -246,7 +246,7 @@ if (!nativeBinding) {
246
246
  throw new Error(`Failed to load native binding`)
247
247
  }
248
248
 
249
- const { expandOutputs, remove, copy, hashArray, hashFile, hashFiles, hashFilesMatchingGlobs, EventType, Watcher, WorkspaceErrors, getConfigFiles, getWorkspaceFilesNative } = nativeBinding
249
+ const { expandOutputs, remove, copy, hashArray, hashFile, hashFiles, hashFilesMatchingGlobs, EventType, Watcher, WorkspaceErrors, getProjectConfigurations, getWorkspaceFilesNative } = nativeBinding
250
250
 
251
251
  module.exports.expandOutputs = expandOutputs
252
252
  module.exports.remove = remove
@@ -258,5 +258,5 @@ module.exports.hashFilesMatchingGlobs = hashFilesMatchingGlobs
258
258
  module.exports.EventType = EventType
259
259
  module.exports.Watcher = Watcher
260
260
  module.exports.WorkspaceErrors = WorkspaceErrors
261
- module.exports.getConfigFiles = getConfigFiles
261
+ module.exports.getProjectConfigurations = getProjectConfigurations
262
262
  module.exports.getWorkspaceFilesNative = getWorkspaceFilesNative
@@ -19,8 +19,9 @@ export declare function createPackageJson(projectName: string, graph: ProjectGra
19
19
  isProduction?: boolean;
20
20
  helperDependencies?: string[];
21
21
  }, fileMap?: ProjectFileMap): PackageJson;
22
- export declare function findProjectsNpmDependencies(projectNode: ProjectGraphProjectNode, graph: ProjectGraph, target: string, options: {
22
+ export declare function findProjectsNpmDependencies(projectNode: ProjectGraphProjectNode, graph: ProjectGraph, target: string, rootPackageJson: PackageJson, options: {
23
23
  helperDependencies?: string[];
24
24
  ignoredDependencies?: string[];
25
+ isProduction?: boolean;
25
26
  }, fileMap?: ProjectFileMap): NpmDeps;
26
27
  export {};
@@ -19,7 +19,11 @@ const path_1 = require("path");
19
19
  function createPackageJson(projectName, graph, options = {}, fileMap = null) {
20
20
  const projectNode = graph.nodes[projectName];
21
21
  const isLibrary = projectNode.type === 'lib';
22
- const npmDeps = findProjectsNpmDependencies(projectNode, graph, options.target, { helperDependencies: options.helperDependencies }, fileMap);
22
+ const rootPackageJson = (0, fileutils_1.readJsonFile)(`${options.root || workspace_root_1.workspaceRoot}/package.json`);
23
+ const npmDeps = findProjectsNpmDependencies(projectNode, graph, options.target, rootPackageJson, {
24
+ helperDependencies: options.helperDependencies,
25
+ isProduction: options.isProduction,
26
+ }, fileMap);
23
27
  // default package.json if one does not exist
24
28
  let packageJson = {
25
29
  name: projectName,
@@ -51,7 +55,6 @@ function createPackageJson(projectName, graph, options = {}, fileMap = null) {
51
55
  (isLibrary && ((_a = rootPackageJson[section]) === null || _a === void 0 ? void 0 : _a[packageName])) ||
52
56
  version);
53
57
  };
54
- const rootPackageJson = (0, fileutils_1.readJsonFile)(`${options.root || workspace_root_1.workspaceRoot}/package.json`);
55
58
  Object.entries(npmDeps.dependencies).forEach(([packageName, version]) => {
56
59
  var _a, _b, _c, _d, _e, _f;
57
60
  if (((_a = rootPackageJson.devDependencies) === null || _a === void 0 ? void 0 : _a[packageName]) &&
@@ -106,7 +109,7 @@ function createPackageJson(projectName, graph, options = {}, fileMap = null) {
106
109
  return packageJson;
107
110
  }
108
111
  exports.createPackageJson = createPackageJson;
109
- function findProjectsNpmDependencies(projectNode, graph, target, options, fileMap) {
112
+ function findProjectsNpmDependencies(projectNode, graph, target, rootPackageJson, options, fileMap) {
110
113
  var _a, _b;
111
114
  if (fileMap == null) {
112
115
  fileMap = ((_a = (0, nx_deps_cache_1.readProjectFileMapCache)()) === null || _a === void 0 ? void 0 : _a.projectFileMap) || {};
@@ -126,7 +129,14 @@ function findProjectsNpmDependencies(projectNode, graph, target, options, fileMa
126
129
  graph.externalNodes[dep].data.version;
127
130
  recursivelyCollectPeerDependencies(dep, graph, npmDeps, seen);
128
131
  });
129
- findAllNpmDeps(fileMap, projectNode, graph, npmDeps, seen, options.ignoredDependencies || [], dependencyInputs, selfInputs);
132
+ // if it's production, we want to ignore all found devDependencies
133
+ const ignoredDependencies = options.isProduction && rootPackageJson.devDependencies
134
+ ? [
135
+ ...(options.ignoredDependencies || []),
136
+ ...Object.keys(rootPackageJson.devDependencies),
137
+ ]
138
+ : options.ignoredDependencies || [];
139
+ findAllNpmDeps(fileMap, projectNode, graph, npmDeps, seen, ignoredDependencies, dependencyInputs, selfInputs);
130
140
  return npmDeps;
131
141
  }
132
142
  exports.findProjectsNpmDependencies = findProjectsNpmDependencies;
@@ -18,4 +18,4 @@ export declare function retrieveWorkspaceFiles(workspaceRoot: string, nxJson: Nx
18
18
  * @param workspaceRoot
19
19
  * @param nxJson
20
20
  */
21
- export declare function retrieveProjectConfigurations(workspaceRoot: string, nxJson: NxJsonConfiguration): Promise<ProjectsConfigurations>;
21
+ export declare function retrieveProjectConfigurations(workspaceRoot: string, nxJson: NxJsonConfiguration): Promise<any>;
@@ -22,27 +22,19 @@ function retrieveWorkspaceFiles(workspaceRoot, nxJson) {
22
22
  perf_hooks_1.performance.mark('native-file-deps:end');
23
23
  perf_hooks_1.performance.measure('native-file-deps', 'native-file-deps:start', 'native-file-deps:end');
24
24
  perf_hooks_1.performance.mark('get-workspace-files:start');
25
- let workspaceFiles;
26
- try {
27
- workspaceFiles = getWorkspaceFilesNative(workspaceRoot, globs);
28
- }
29
- catch (e) {
30
- // If the error is a parse error from Rust, then use the JS readJsonFile function to write a pretty error message
31
- if (e.code === "ParseError" /* WorkspaceErrors.ParseError */) {
32
- (0, fileutils_1.readJsonFile)((0, path_1.join)(workspaceRoot, e.message));
33
- // readJsonFile should always fail, but if it doesn't, then throw the original error
34
- throw e;
35
- }
36
- else {
37
- throw e;
38
- }
39
- }
25
+ const { projectConfigurations, projectFileMap, globalFiles } = getWorkspaceFilesNative(workspaceRoot, globs, (configs) => {
26
+ const projectConfigurations = createProjectConfigurations(workspaceRoot, nxJson, configs);
27
+ return projectConfigurations.projects;
28
+ });
40
29
  perf_hooks_1.performance.mark('get-workspace-files:end');
41
30
  perf_hooks_1.performance.measure('get-workspace-files', 'get-workspace-files:start', 'get-workspace-files:end');
42
31
  return {
43
- allWorkspaceFiles: buildAllWorkspaceFiles(workspaceFiles.projectFileMap, workspaceFiles.globalFiles),
44
- projectFileMap: workspaceFiles.projectFileMap,
45
- projectConfigurations: createProjectConfigurations(workspaceRoot, nxJson, workspaceFiles.configFiles),
32
+ allWorkspaceFiles: buildAllWorkspaceFiles(projectFileMap, globalFiles),
33
+ projectFileMap,
34
+ projectConfigurations: {
35
+ version: 2,
36
+ projects: projectConfigurations,
37
+ },
46
38
  };
47
39
  });
48
40
  }
@@ -55,10 +47,12 @@ exports.retrieveWorkspaceFiles = retrieveWorkspaceFiles;
55
47
  */
56
48
  function retrieveProjectConfigurations(workspaceRoot, nxJson) {
57
49
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
58
- const { getConfigFiles } = require('../../native');
50
+ const { getProjectConfigurations } = require('../../native');
59
51
  const globs = yield configurationGlobs(workspaceRoot, nxJson);
60
- const configPaths = getConfigFiles(workspaceRoot, globs);
61
- return createProjectConfigurations(workspaceRoot, nxJson, configPaths);
52
+ return getProjectConfigurations(workspaceRoot, globs, (configs) => {
53
+ const projectConfigurations = createProjectConfigurations(workspaceRoot, nxJson, configs);
54
+ return projectConfigurations.projects;
55
+ });
62
56
  });
63
57
  }
64
58
  exports.retrieveProjectConfigurations = retrieveProjectConfigurations;
@@ -74,14 +68,17 @@ function createProjectConfigurations(workspaceRoot, nxJson, configFiles) {
74
68
  perf_hooks_1.performance.mark('build-project-configs:start');
75
69
  let projectConfigurations = mergeTargetDefaultsIntoProjectDescriptions((0, workspaces_1.buildProjectsConfigurationsFromProjectPaths)(nxJson, configFiles, (path) => (0, fileutils_1.readJsonFile)((0, path_1.join)(workspaceRoot, path))), nxJson);
76
70
  if ((0, angular_json_1.shouldMergeAngularProjects)(workspaceRoot, false)) {
77
- projectConfigurations.projects = (0, angular_json_1.mergeAngularJsonAndProjects)(projectConfigurations.projects, workspaceRoot);
71
+ projectConfigurations = (0, angular_json_1.mergeAngularJsonAndProjects)(projectConfigurations, workspaceRoot);
78
72
  }
79
73
  perf_hooks_1.performance.mark('build-project-configs:end');
80
74
  perf_hooks_1.performance.measure('build-project-configs', 'build-project-configs:start', 'build-project-configs:end');
81
- return projectConfigurations;
75
+ return {
76
+ version: 2,
77
+ projects: projectConfigurations,
78
+ };
82
79
  }
83
- function mergeTargetDefaultsIntoProjectDescriptions(config, nxJson) {
84
- for (const proj of Object.values(config.projects)) {
80
+ function mergeTargetDefaultsIntoProjectDescriptions(projects, nxJson) {
81
+ for (const proj of Object.values(projects)) {
85
82
  if (proj.targets) {
86
83
  for (const targetName of Object.keys(proj.targets)) {
87
84
  const projectTargetDefinition = proj.targets[targetName];
@@ -92,7 +89,7 @@ function mergeTargetDefaultsIntoProjectDescriptions(config, nxJson) {
92
89
  }
93
90
  }
94
91
  }
95
- return config;
92
+ return projects;
96
93
  }
97
94
  function configurationGlobs(workspaceRoot, nxJson) {
98
95
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
@@ -1,5 +1,6 @@
1
1
  export type PackageManager = 'yarn' | 'pnpm' | 'npm';
2
2
  export interface PackageManagerCommands {
3
+ preInstall?: string;
3
4
  install: string;
4
5
  ciInstall: string;
5
6
  add: string;
@@ -47,6 +47,9 @@ function getPackageManagerCommand(packageManager = detectPackageManager(), root
47
47
  const yarnVersion = getPackageManagerVersion('yarn');
48
48
  const useBerry = (0, semver_1.gte)(yarnVersion, '2.0.0');
49
49
  return {
50
+ preInstall: useBerry
51
+ ? 'yarn set version stable'
52
+ : 'yarn set version classic',
50
53
  install: 'yarn',
51
54
  ciInstall: useBerry
52
55
  ? 'yarn install --immutable'