Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(angular): handle not provided path when generating a component without the project option #13877

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -42,6 +42,20 @@ export class ExampleComponent {
"
`;

exports[`component Generator --path should infer project from path and generate component correctly 1`] = `
"import { Component } from '@angular/core';

@Component({
selector: 'example',
templateUrl: './example.component.html',
styleUrls: ['./example.component.css']
})
export class ExampleComponent {

}
"
`;

exports[`component Generator secondary entry points should create the component correctly and export it in the entry point 1`] = `
"import { Component } from '@angular/core';

Expand Down
Expand Up @@ -2,7 +2,6 @@ import type { Tree } from '@nrwl/devkit';
import {
createProjectGraphAsync,
joinPathFragments,
readCachedProjectGraph,
readProjectConfiguration,
readWorkspaceConfiguration,
} from '@nrwl/devkit';
Expand All @@ -15,7 +14,10 @@ import {
async function findProjectFromOptions(options: Schema) {
const projectGraph = await createProjectGraphAsync();
const projectRootMappings = createProjectRootMappings(projectGraph.nodes);
return findProjectForPath(options.path, projectRootMappings);

// path can be undefined when running on the root of the workspace, we default to the root
// to handle standalone layouts
return findProjectForPath(options.path || '', projectRootMappings);
}

export async function normalizeOptions(
Expand All @@ -26,6 +28,22 @@ export async function normalizeOptions(
options.project ??
(await findProjectFromOptions(options)) ??
readWorkspaceConfiguration(tree).defaultProject;

if (!project) {
// path is hidden, so if not provided we don't suggest setting it
if (!options.path) {
throw new Error(
'No "project" was specified and "defaultProject" is not set in the workspace configuration. Please provide the "project" option and try again.'
);
}

// path was provided, so it's wrong and we should mention it
throw new Error(
'The provided "path" is wrong and no "project" was specified and "defaultProject" is not set in the workspace configuration. ' +
'Please provide a correct "path" or provide the "project" option instead and try again.'
);
}

const { projectType, root, sourceRoot } = readProjectConfiguration(
tree,
project
Expand Down
79 changes: 79 additions & 0 deletions packages/angular/src/generators/component/component.spec.ts
@@ -1,7 +1,16 @@
import type { ProjectGraph } from '@nrwl/devkit';
import { addProjectConfiguration, writeJson } from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import componentGenerator from './component';

let projectGraph: ProjectGraph;
jest.mock('@nrwl/devkit', () => {
return {
...jest.requireActual('@nrwl/devkit'),
createProjectGraphAsync: jest.fn().mockImplementation(() => projectGraph),
};
});

describe('component Generator', () => {
it('should create the component correctly and export it in the entry point when "export=true"', async () => {
// ARRANGE
Expand Down Expand Up @@ -406,6 +415,46 @@ describe('component Generator', () => {
);
});

it('should infer project from path and generate component correctly', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'lib1', {
projectType: 'library',
sourceRoot: 'libs/lib1/src',
root: 'libs/lib1',
});
tree.write(
'libs/lib1/src/lib/lib.module.ts',
`
import { NgModule } from '@angular/core';

@NgModule({
declarations: [],
exports: []
})
export class LibModule {}`
);
projectGraph = {
nodes: {
lib1: { name: 'lib1', type: 'lib', data: { root: 'libs/lib1' } },
},
dependencies: {},
};

// ACT
await componentGenerator(tree, {
name: 'example',
path: 'libs/lib1/src/lib/mycomp',
});

// ASSERT
const componentSource = tree.read(
'libs/lib1/src/lib/mycomp/example/example.component.ts',
'utf-8'
);
expect(componentSource).toMatchSnapshot();
});

it('should throw if the path specified is not under the project root', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
Expand Down Expand Up @@ -437,6 +486,36 @@ describe('component Generator', () => {
})
).rejects.toThrow();
});

it('should throw when path and projects are not provided and defaultProject is not set', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'lib1', {
projectType: 'library',
sourceRoot: 'libs/lib1/src',
root: 'libs/lib1',
});
tree.write(
'libs/lib1/src/lib/lib.module.ts',
`
import { NgModule } from '@angular/core';

@NgModule({
declarations: [],
exports: []
})
export class LibModule {}`
);
tree.write('libs/lib1/src/index.ts', 'export * from "./lib/lib.module";');

// ACT & ASSERT
await expect(
componentGenerator(tree, {
name: 'example',
export: false,
})
).rejects.toThrow();
});
});

describe('--module', () => {
Expand Down
Expand Up @@ -2,7 +2,6 @@ import type { Tree } from '@nrwl/devkit';
import {
createProjectGraphAsync,
joinPathFragments,
readCachedProjectGraph,
readProjectConfiguration,
readWorkspaceConfiguration,
} from '@nrwl/devkit';
Expand All @@ -15,7 +14,10 @@ import {
async function findProjectFromOptions(options: Schema) {
const projectGraph = await createProjectGraphAsync();
const projectRootMappings = createProjectRootMappings(projectGraph.nodes);
return findProjectForPath(options.path, projectRootMappings);

// path can be undefined when running on the root of the workspace, we default to the root
// to handle standalone layouts
return findProjectForPath(options.path || '', projectRootMappings);
}

export async function normalizeOptions(
Expand All @@ -26,6 +28,22 @@ export async function normalizeOptions(
options.project ??
(await findProjectFromOptions(options)) ??
readWorkspaceConfiguration(tree).defaultProject;

if (!project) {
// path is hidden, so if not provided we don't suggest setting it
if (!options.path) {
throw new Error(
'No "project" was specified and "defaultProject" is not set in the workspace configuration. Please provide the "project" option and try again.'
);
}

// path was provided, so it's wrong and we should mention it
throw new Error(
'The provided "path" is wrong and no "project" was specified and "defaultProject" is not set in the workspace configuration. ' +
'Please provide a correct "path" or provide the "project" option instead and try again.'
);
}

const { projectType, root, sourceRoot } = readProjectConfiguration(
tree,
project
Expand Down