Skip to content

Commit

Permalink
fix(angular): handle not provided path when generating a component wi…
Browse files Browse the repository at this point in the history
…thout the project option (#13877)
  • Loading branch information
leosvelperez committed Dec 19, 2022
1 parent bbfc0fb commit 4e54b1a
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 4 deletions.
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
22 changes: 20 additions & 2 deletions packages/angular/src/generators/component/lib/normalize-options.ts
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

0 comments on commit 4e54b1a

Please sign in to comment.