Skip to content

Commit 3dbbfd7

Browse files
authored
feat(devkit): allow updating package json based projects (#27138)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior Calling `updateProjectConfiguration` on a package json based project fails ## Expected Behavior Calling `updateProjectConfiguration` on a package json based project works ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #26530
1 parent 9a556f4 commit 3dbbfd7

File tree

4 files changed

+131
-28
lines changed

4 files changed

+131
-28
lines changed

.nxignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
nx-dev/**/jest.config.js
2-
.next
2+
.next

packages/nx/src/generators/utils/project-configuration.spec.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,5 +277,57 @@ describe('project configuration', () => {
277277
root: 'proj',
278278
});
279279
});
280+
281+
it('should handle reading + writing project configuration', () => {
282+
writeJson(tree, 'proj/package.json', {
283+
name: 'proj',
284+
nx: {},
285+
});
286+
287+
const proj = readProjectConfiguration(tree, 'proj');
288+
expect(proj).toEqual({
289+
name: 'proj',
290+
root: 'proj',
291+
});
292+
293+
updateProjectConfiguration(tree, 'proj', {
294+
name: 'proj',
295+
root: 'proj',
296+
sourceRoot: 'proj/src',
297+
targets: {
298+
build: {
299+
command: 'echo "building"',
300+
},
301+
},
302+
});
303+
304+
const updatedProj = readProjectConfiguration(tree, 'proj');
305+
expect(updatedProj).toEqual({
306+
name: 'proj',
307+
root: 'proj',
308+
sourceRoot: 'proj/src',
309+
targets: {
310+
build: {
311+
command: 'echo "building"',
312+
},
313+
},
314+
});
315+
316+
expect(tree.read('proj/package.json', 'utf-8')).toMatchInlineSnapshot(`
317+
"{
318+
"name": "proj",
319+
"nx": {
320+
"sourceRoot": "proj/src",
321+
"targets": {
322+
"build": {
323+
"command": "echo \\"building\\""
324+
}
325+
}
326+
}
327+
}
328+
"
329+
`);
330+
expect(tree.exists('proj/project.json')).toBeFalsy();
331+
});
280332
});
281333
});

packages/nx/src/generators/utils/project-configuration.ts

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { minimatch } from 'minimatch';
2-
import { basename, join, relative } from 'path';
2+
import { basename, dirname, join, relative } from 'path';
33

4-
import {
5-
buildProjectConfigurationFromPackageJson,
6-
getGlobPatternsFromPackageManagerWorkspaces,
7-
} from '../../plugins/package-json';
4+
import { getGlobPatternsFromPackageManagerWorkspaces } from '../../plugins/package-json';
85
import { buildProjectFromProjectJson } from '../../plugins/project-json/build-nodes/project-json';
96
import { renamePropertyWithStableKeys } from '../../adapter/angular-json';
107
import {
@@ -23,6 +20,7 @@ import { readJson, writeJson } from './json';
2320
import { readNxJson } from './nx-json';
2421

2522
import type { Tree } from '../tree';
23+
import { toProjectName } from '../../config/to-project-name';
2624

2725
export { readNxJson, updateNxJson } from './nx-json';
2826

@@ -82,17 +80,73 @@ export function updateProjectConfiguration(
8280
projectName: string,
8381
projectConfiguration: ProjectConfiguration
8482
): void {
83+
if (
84+
tree.exists(joinPathFragments(projectConfiguration.root, 'project.json'))
85+
) {
86+
updateProjectConfigurationInProjectJson(
87+
tree,
88+
projectName,
89+
projectConfiguration
90+
);
91+
} else if (
92+
tree.exists(joinPathFragments(projectConfiguration.root, 'package.json'))
93+
) {
94+
updateProjectConfigurationInPackageJson(
95+
tree,
96+
projectName,
97+
projectConfiguration
98+
);
99+
} else {
100+
throw new Error(
101+
`Cannot update Project ${projectName} at ${projectConfiguration.root}. It either doesn't exist yet, or may not use project.json for configuration. Use \`addProjectConfiguration()\` instead if you want to create a new project.`
102+
);
103+
}
104+
}
105+
106+
function updateProjectConfigurationInPackageJson(
107+
tree: Tree,
108+
projectName: string,
109+
projectConfiguration: ProjectConfiguration
110+
) {
111+
const packageJsonFile = joinPathFragments(
112+
projectConfiguration.root,
113+
'package.json'
114+
);
115+
116+
const packageJson = readJson<PackageJson>(tree, packageJsonFile);
117+
118+
if (packageJson.name === projectConfiguration.name ?? projectName) {
119+
delete projectConfiguration.name;
120+
}
121+
122+
if (
123+
projectConfiguration.targets &&
124+
!Object.keys(projectConfiguration.targets).length
125+
) {
126+
delete projectConfiguration.targets;
127+
}
128+
129+
packageJson.nx = {
130+
...packageJson.nx,
131+
...projectConfiguration,
132+
root: undefined,
133+
};
134+
135+
writeJson(tree, packageJsonFile, packageJson);
136+
}
137+
138+
function updateProjectConfigurationInProjectJson(
139+
tree: Tree,
140+
projectName: string,
141+
projectConfiguration: ProjectConfiguration
142+
) {
85143
const projectConfigFile = joinPathFragments(
86144
projectConfiguration.root,
87145
'project.json'
88146
);
89147

90-
if (!tree.exists(projectConfigFile)) {
91-
throw new Error(
92-
`Cannot update Project ${projectName} at ${projectConfiguration.root}. It either doesn't exist yet, or may not use project.json for configuration. Use \`addProjectConfiguration()\` instead if you want to create a new project.`
93-
);
94-
}
95148
handleEmptyTargets(projectName, projectConfiguration);
149+
96150
writeJson(tree, projectConfigFile, {
97151
name: projectConfiguration.name ?? projectName,
98152
$schema: getRelativeProjectJsonSchemaPath(tree, projectConfiguration),
@@ -215,21 +269,22 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
215269
);
216270
} else if (basename(projectFile) === 'package.json') {
217271
const packageJson = readJson<PackageJson>(tree, projectFile);
218-
const config = buildProjectConfigurationFromPackageJson(
219-
packageJson,
220-
tree.root,
221-
projectFile,
222-
readNxJson(tree)
223-
);
272+
273+
// We don't want to have all of the extra inferred stuff in here, as
274+
// when generators update the project they shouldn't inline that stuff.
275+
// so rather than using `buildProjectFromPackageJson` and stripping it out
276+
// we are going to build the config manually.
277+
const config = {
278+
root: dirname(projectFile),
279+
name: packageJson.name ?? toProjectName(projectFile),
280+
...packageJson.nx,
281+
};
224282
if (!rootMap[config.root]) {
225283
mergeProjectConfigurationIntoRootMap(
226284
rootMap,
227285
// Inferred targets, tags, etc don't show up when running generators
228286
// This is to help avoid running into issues when trying to update the workspace
229-
{
230-
name: config.name,
231-
root: config.root,
232-
},
287+
config,
233288
undefined,
234289
undefined,
235290
true

packages/nx/src/utils/package-json.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { existsSync } from 'fs';
22
import { dirname, join } from 'path';
33
import {
4-
InputDefinition,
4+
ProjectConfiguration,
55
ProjectMetadata,
66
TargetConfiguration,
77
} from '../config/workspace-json-project-json';
@@ -13,12 +13,8 @@ import {
1313
getPackageManagerCommand,
1414
} from './package-manager';
1515

16-
export interface NxProjectPackageJsonConfiguration {
17-
name?: string;
18-
implicitDependencies?: string[];
19-
tags?: string[];
20-
namedInputs?: { [inputName: string]: (string | InputDefinition)[] };
21-
targets?: Record<string, TargetConfiguration>;
16+
export interface NxProjectPackageJsonConfiguration
17+
extends Partial<ProjectConfiguration> {
2218
includedScripts?: string[];
2319
}
2420

0 commit comments

Comments
 (0)