Skip to content

Commit

Permalink
fix(angular): handle newProjectRoot correctly when generating apps an…
Browse files Browse the repository at this point in the history
…d libs (#9255)
  • Loading branch information
leosvelperez committed Mar 10, 2022
1 parent 261b35d commit 081ff42
Show file tree
Hide file tree
Showing 14 changed files with 129 additions and 81 deletions.
10 changes: 4 additions & 6 deletions packages/angular/src/generators/application/application.spec.ts
Expand Up @@ -159,19 +159,17 @@ describe('app', () => {
expect(appE2eSpec).toContain('Welcome my-app-with-prefix');
});

// TODO: this should work
// This has been carried over from the Angular Devkit Schematic
// It seems like Jest is failing as it's trying to look for the
// tsconfig in the incorrect place
xit('should work if the new project root is changed', async () => {
it('should work if the new project root is changed', async () => {
// ARRANGE
updateJson(appTree, '/workspace.json', (json) => ({
...json,
newProjectRoot: 'newProjectRoot',
}));

// ACT
await generateApp(appTree);
await generateApp(appTree, 'my-app', {
e2eTestRunner: E2eTestRunner.Protractor,
});

// ASSERT
expect(appTree.exists('apps/my-app/src/main.ts')).toEqual(true);
Expand Down
28 changes: 9 additions & 19 deletions packages/angular/src/generators/application/application.ts
@@ -1,9 +1,7 @@
import {
formatFiles,
getWorkspacePath,
installPackagesTask,
moveFilesToNewDirectory,
readJson,
Tree,
} from '@nrwl/devkit';
import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
Expand Down Expand Up @@ -36,20 +34,6 @@ export async function applicationGenerator(
) {
const options = normalizeOptions(host, schema);

// Determine the roots where @schematics/angular will place the projects
// This is not where the projects actually end up
const workspaceJsonPath = getWorkspacePath(host);
let newProjectRoot = null;
if (workspaceJsonPath) {
({ newProjectRoot } = readJson(host, workspaceJsonPath));
}
const appProjectRoot = newProjectRoot
? `${newProjectRoot}/${options.name}`
: options.name;
const e2eProjectRoot = newProjectRoot
? `${newProjectRoot}/${options.e2eProjectName}`
: `${options.name}/e2e`;

await angularInitGenerator(host, {
...options,
skipFormat: true,
Expand All @@ -72,9 +56,15 @@ export async function applicationGenerator(
skipPackageJson: options.skipPackageJson,
});

createFiles(host, options, appProjectRoot);
if (options.ngCliSchematicAppRoot !== options.appProjectRoot) {
moveFilesToNewDirectory(
host,
options.ngCliSchematicAppRoot,
options.appProjectRoot
);
}

moveFilesToNewDirectory(host, appProjectRoot, options.appProjectRoot);
createFiles(host, options);
updateConfigFiles(host, options);
updateAppComponentTemplate(host, options);

Expand Down Expand Up @@ -114,7 +104,7 @@ export async function applicationGenerator(

addLinting(host, options);
await addUnitTestRunner(host, options);
await addE2e(host, options, e2eProjectRoot);
await addE2e(host, options);
updateEditorTsConfig(host, options);

if (options.backendProject) {
Expand Down
17 changes: 2 additions & 15 deletions packages/angular/src/generators/application/lib/add-e2e.ts
Expand Up @@ -12,24 +12,11 @@ import { convertToNxProjectGenerator } from '@nrwl/workspace';
import { Linter, lintProjectGenerator } from '@nrwl/linter';
import { getWorkspaceLayout, joinPathFragments } from '@nrwl/devkit';

/**
* Add E2E Config
*
* @param tree Nx Devkit Virtual Tree
* @param options Normalized Schema
* @param e2eProjectRoot Raw E2E Project Root that Angular tries to write to
*
* @returns Function to run to add Cypres config after intial app files have been moved to correct location
*/
export async function addE2e(
tree: Tree,
options: NormalizedSchema,
e2eProjectRoot: string
) {
export async function addE2e(tree: Tree, options: NormalizedSchema) {
if (options.e2eTestRunner === E2eTestRunner.Protractor) {
await addProtractor(tree, options);
} else {
removeScaffoldedE2e(tree, options, e2eProjectRoot);
removeScaffoldedE2e(tree, options, options.ngCliSchematicE2ERoot);
}

if (options.e2eTestRunner === 'cypress') {
Expand Down
Expand Up @@ -3,13 +3,7 @@ import { generateFiles, joinPathFragments } from '@nrwl/devkit';
import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript';
import type { NormalizedSchema } from './normalized-schema';

export function createFiles(
host: Tree,
options: NormalizedSchema,
appProjectRoot: string
) {
host.delete(`${appProjectRoot}/src/favicon.ico`);

export function createFiles(host: Tree, options: NormalizedSchema) {
generateFiles(
host,
joinPathFragments(__dirname, '../files'),
Expand Down
@@ -1,4 +1,9 @@
import { joinPathFragments, Tree } from '@nrwl/devkit';
import {
getWorkspacePath,
joinPathFragments,
readJson,
Tree,
} from '@nrwl/devkit';
import type { Schema } from '../schema';
import type { NormalizedSchema } from './normalized-schema';

Expand Down Expand Up @@ -35,6 +40,20 @@ export function normalizeOptions(

options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault;

// Determine the roots where @schematics/angular will place the projects
// This might not be where the projects actually end up
const workspaceJsonPath = getWorkspacePath(host);
let newProjectRoot = null;
if (workspaceJsonPath) {
({ newProjectRoot } = readJson(host, workspaceJsonPath));
}
const ngCliSchematicAppRoot = newProjectRoot
? `${newProjectRoot}/${appProjectName}`
: appProjectName;
const ngCliSchematicE2ERoot = newProjectRoot
? `${newProjectRoot}/${e2eProjectName}`
: `${appProjectName}/e2e`;

// Set defaults and then overwrite with user options
return {
style: 'css',
Expand All @@ -54,5 +73,7 @@ export function normalizeOptions(
e2eProjectRoot,
e2eProjectName,
parsedTags,
ngCliSchematicAppRoot,
ngCliSchematicE2ERoot,
};
}
Expand Up @@ -10,4 +10,6 @@ export interface NormalizedSchema extends Schema {
e2eProjectName: string;
e2eProjectRoot: string;
parsedTags: string[];
ngCliSchematicAppRoot: string;
ngCliSchematicE2ERoot: string;
}
Expand Up @@ -38,42 +38,44 @@ function updateAppAndE2EProjectConfigurations(
options: NormalizedSchema
) {
// workspace.json
const project = readProjectConfiguration(host, options.name);
let project = readProjectConfiguration(host, options.name);

let fixedProject = replaceAppNameWithPath(
project,
options.name,
options.appProjectRoot
);
if (options.ngCliSchematicAppRoot !== options.appProjectRoot) {
project = replaceAppNameWithPath(
project,
options.ngCliSchematicAppRoot,
options.appProjectRoot
);
}

delete fixedProject.targets.test;
delete project.targets.test;

// Ensure the outputs property comes after the executor for
// better readability.
const { executor, ...rest } = fixedProject.targets.build;
fixedProject.targets.build = {
const { executor, ...rest } = project.targets.build;
project.targets.build = {
executor,
outputs: ['{options.outputPath}'],
...rest,
};

if (fixedProject.generators) {
delete fixedProject.generators;
if (project.generators) {
delete project.generators;
}

if (options.port) {
fixedProject.targets.serve = {
...fixedProject.targets.serve,
project.targets.serve = {
...project.targets.serve,
options: {
...fixedProject.targets.serve.options,
...project.targets.serve.options,
port: options.port,
},
};
}

fixedProject.tags = options.parsedTags;
project.tags = options.parsedTags;

updateProjectConfiguration(host, options.name, fixedProject);
updateProjectConfiguration(host, options.name, project);

if (options.unitTestRunner === UnitTestRunner.None) {
host.delete(`${options.appProjectRoot}/src/app/app.component.spec.ts`);
Expand Down
20 changes: 19 additions & 1 deletion packages/angular/src/generators/library/lib/normalize-options.ts
@@ -1,4 +1,10 @@
import { getWorkspaceLayout, joinPathFragments, Tree } from '@nrwl/devkit';
import {
getWorkspaceLayout,
getWorkspacePath,
joinPathFragments,
readJson,
Tree,
} from '@nrwl/devkit';
import { Schema } from '../schema';
import { NormalizedSchema } from './normalized-schema';
import { names } from '@nrwl/devkit';
Expand Down Expand Up @@ -51,6 +57,17 @@ export function normalizeOptions(
const importPath =
options.importPath || `@${defaultPrefix}/${projectDirectory}`;

// Determine the roots where @schematics/angular will place the projects
// This might not be where the projects actually end up
const workspaceJsonPath = getWorkspacePath(host);
let newProjectRoot = null;
if (workspaceJsonPath) {
({ newProjectRoot } = readJson(host, workspaceJsonPath));
}
const ngCliSchematicLibRoot = newProjectRoot
? `${newProjectRoot}/${projectName}`
: projectName;

return {
...options,
linter: options.linter ?? Linter.EsLint,
Expand All @@ -65,5 +82,6 @@ export function normalizeOptions(
parsedTags,
fileName,
importPath,
ngCliSchematicLibRoot,
};
}
Expand Up @@ -12,4 +12,5 @@ export interface NormalizedSchema extends Schema {
moduleName: string;
projectDirectory: string;
parsedTags: string[];
ngCliSchematicLibRoot: string;
}
24 changes: 13 additions & 11 deletions packages/angular/src/generators/library/lib/update-project.ts
Expand Up @@ -129,23 +129,25 @@ function createFiles(host: Tree, options: NormalizedSchema) {
}

function fixProjectWorkspaceConfig(host: Tree, options: NormalizedSchema) {
const project = readProjectConfiguration(host, options.name);
let project = readProjectConfiguration(host, options.name);
project.tags = options.parsedTags;

const fixedProject = replaceAppNameWithPath(
project,
options.name,
options.projectRoot
);
if (options.ngCliSchematicLibRoot !== options.projectRoot) {
project = replaceAppNameWithPath(
project,
options.ngCliSchematicLibRoot,
options.projectRoot
);
}

if (!options.publishable && !options.buildable) {
delete fixedProject.targets.build;
delete project.targets.build;
} else {
// Set the right builder for the type of library.
// Ensure the outputs property comes after the builder for
// better readability.
const { executor, ...rest } = fixedProject.targets.build;
fixedProject.targets.build = {
const { executor, ...rest } = project.targets.build;
project.targets.build = {
executor: options.publishable
? '@nrwl/angular:package'
: '@nrwl/angular:ng-packagr-lite',
Expand All @@ -160,9 +162,9 @@ function fixProjectWorkspaceConfig(host: Tree, options: NormalizedSchema) {
};
}

delete fixedProject.targets.test;
delete project.targets.test;

updateProjectConfiguration(host, options.name, fixedProject);
updateProjectConfiguration(host, options.name, project);
}

function updateProjectTsConfig(host: Tree, options: NormalizedSchema) {
Expand Down
25 changes: 25 additions & 0 deletions packages/angular/src/generators/library/library.spec.ts
Expand Up @@ -457,6 +457,31 @@ describe('lib', () => {
).toBeFalsy();
});

it('should work if the new project root is changed', async () => {
// ARRANGE
updateJson(tree, 'workspace.json', (json) => ({
...json,
newProjectRoot: 'newProjectRoot',
}));

// ACT
await runLibraryGeneratorWithOpts();

// ASSERT
expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy();
expect(tree.exists('libs/my-lib/src/lib/my-lib.module.ts')).toBeTruthy();
expect(
tree.exists('libs/my-lib/src/lib/my-lib.component.ts')
).toBeFalsy();
expect(
tree.exists('libs/my-lib/src/lib/my-lib.component.spec.ts')
).toBeFalsy();
expect(tree.exists('libs/my-lib/src/lib/my-lib.service.ts')).toBeFalsy();
expect(
tree.exists('libs/my-lib/src/lib/my-lib.service.spec.ts')
).toBeFalsy();
});

it('should default the prefix to npmScope', async () => {
// ACT
await runLibraryGeneratorWithOpts();
Expand Down
8 changes: 7 additions & 1 deletion packages/angular/src/generators/library/library.ts
Expand Up @@ -63,7 +63,13 @@ export async function libraryGenerator(host: Tree, schema: Partial<Schema>) {
skipTsConfig: true,
});

moveFilesToNewDirectory(host, options.name, options.projectRoot);
if (options.ngCliSchematicLibRoot !== options.projectRoot) {
moveFilesToNewDirectory(
host,
options.ngCliSchematicLibRoot,
options.projectRoot
);
}
await updateProject(host, options);
updateTsConfig(host, options);
await addUnitTestRunner(host, options);
Expand Down
4 changes: 3 additions & 1 deletion packages/devkit/src/generators/project-configuration.ts
Expand Up @@ -189,7 +189,9 @@ export function updateWorkspaceConfiguration(
...json,
version: workspaceConfig.version,
};
delete (config as any).newProjectRoot;
if (!(workspaceConfig as any).newProjectRoot) {
delete (config as any).newProjectRoot;
}
return config;
});
}
Expand Down
Expand Up @@ -2,12 +2,12 @@

exports[`preset should create files (preset = angular) 1`] = `
Array [
"src",
"tsconfig.editor.json",
"tsconfig.json",
".browserslistrc",
"tsconfig.app.json",
"tsconfig.spec.json",
"src",
"tsconfig.editor.json",
"tsconfig.json",
".eslintrc.json",
"jest.config.js",
]
Expand Down

0 comments on commit 081ff42

Please sign in to comment.