Skip to content

Commit

Permalink
feat(core): provide a hint when project.json has empty targets
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo committed Feb 27, 2024
1 parent c207081 commit 6e50324
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 4 deletions.
Expand Up @@ -62,6 +62,7 @@ exports[`app generated files content - as-provided general application should co
"$schema": "../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "my-app/src",
"// targets": "to see all targets run: nx show project my-app --web",
"targets": {}
}
"
Expand Down
4 changes: 4 additions & 0 deletions packages/nx/schemas/project-schema.json
Expand Up @@ -11,6 +11,10 @@
"$ref": "#/definitions/inputs"
}
},
"// targets": {
"type": "string",
"description": "Hint provided when targets are inferred and empty in project.json."
},
"targets": {
"type": "object",
"description": "Configures all the targets which define what tasks you can run against the project",
Expand Down
77 changes: 74 additions & 3 deletions packages/nx/src/generators/utils/project-configuration.spec.ts
Expand Up @@ -21,7 +21,6 @@ const projectConfiguration: ProjectConfiguration = {
name: 'test',
root: 'libs/test',
sourceRoot: 'libs/test/src',
targets: {},
};

describe('project configuration', () => {
Expand All @@ -32,20 +31,92 @@ describe('project configuration', () => {
});

it('should create project.json file when adding a project if standalone is true', () => {
addProjectConfiguration(tree, 'test', projectConfiguration);
addProjectConfiguration(tree, 'test', {
...projectConfiguration,
targets: {
test: {},
},
});

expect(readProjectConfiguration(tree, 'test')).toMatchInlineSnapshot(`
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "test",
"root": "libs/test",
"sourceRoot": "libs/test/src",
"targets": {},
"targets": {
"test": {},
},
}
`);
expect(tree.exists('libs/test/project.json')).toBeTruthy();
});

it('should add a comment to show project details when targets are missing', () => {
addProjectConfiguration(tree, 'test', {
...projectConfiguration,
targets: {},
});

expect(readProjectConfiguration(tree, 'test')).toMatchInlineSnapshot(`
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "test",
"root": "libs/test",
"sourceRoot": "libs/test/src",
"targets": {},
}
`);

expect(tree.read('libs/test/project.json', 'utf-8')).toMatchInlineSnapshot(`
"{
"name": "test",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/test/src",
"// targets": "to see all targets run: nx show project test --web",
"targets": {}
}
"
`);

// Adding a target removes the "// targets" comment.
updateProjectConfiguration(tree, 'test', {
...projectConfiguration,
targets: {
test: {},
},
});

expect(tree.read('libs/test/project.json', 'utf-8')).toMatchInlineSnapshot(`
"{
"name": "test",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/test/src",
"targets": {
"test": {}
}
}
"
`);

// Emptying out targets add "// targets" comment back.
updateProjectConfiguration(tree, 'test', {
...projectConfiguration,
targets: {},
});

expect(tree.read('libs/test/project.json', 'utf-8')).toMatchInlineSnapshot(`
"{
"name": "test",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/test/src",
"// targets": "to see all targets run: nx show project test --web",
"targets": {}
}
"
`);
});

it('should update project.json file when updating a project', () => {
addProjectConfiguration(tree, 'test', projectConfiguration);
const expectedProjectConfig = {
Expand Down
25 changes: 24 additions & 1 deletion packages/nx/src/generators/utils/project-configuration.ts
Expand Up @@ -64,6 +64,9 @@ export function addProjectConfiguration(
}

delete (projectConfiguration as any).$schema;

handleEmptyTargets(projectName, projectConfiguration);

writeJson(tree, projectConfigFile, {
name: projectName,
$schema: getRelativeProjectJsonSchemaPath(tree, projectConfiguration),
Expand Down Expand Up @@ -94,6 +97,7 @@ export function updateProjectConfiguration(
`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.`
);
}
handleEmptyTargets(projectName, projectConfiguration);
writeJson(tree, projectConfigFile, {
name: projectConfiguration.name ?? projectName,
$schema: getRelativeProjectJsonSchemaPath(tree, projectConfiguration),
Expand Down Expand Up @@ -192,7 +196,7 @@ function readAndCombineAllProjectConfigurations(tree: Tree): {
'**/project.json',
'project.json',
...getGlobPatternsFromPackageManagerWorkspaces(tree.root, (p) =>
readJson(tree, p)
readJson(tree, p, { expectComments: true })
),
];
const projectGlobPatterns = configurationGlobs([
Expand Down Expand Up @@ -328,3 +332,22 @@ function toNewFormat(w: any): ProjectsConfigurations {
}
return w;
}

function handleEmptyTargets(
projectName: string,
projectConfiguration: ProjectConfiguration
): void {
if (
projectConfiguration.targets &&
!Object.keys(projectConfiguration.targets).length
) {
// Re-order `targets` to appear after the `// target` comment.
delete projectConfiguration.targets;
projectConfiguration[
'// targets'
] = `to see all targets run: nx show project ${projectName} --web`;
projectConfiguration.targets = {};
} else {
delete projectConfiguration['// targets'];
}
}
Expand Up @@ -307,6 +307,9 @@ export function readProjectConfigurationsFromRootMap(
const errors: Map<string, string[]> = new Map();

for (const [root, configuration] of projectRootMap.entries()) {
// We're setting `// targets` as a comment `targets` is empty due to Project Crystal.
// Strip it before returning configuration for usage.
if (configuration['// targets']) delete configuration['// targets'];
if (!configuration.name) {
try {
const { name } = readJsonFile(join(root, 'package.json'));
Expand Down

0 comments on commit 6e50324

Please sign in to comment.