Skip to content

Commit

Permalink
fix(misc): handle moving to a subfolder which results in the same pro…
Browse files Browse the repository at this point in the history
…ject name and normalize import path
  • Loading branch information
leosvelperez committed Jul 26, 2021
1 parent 9e82524 commit 64b560e
Show file tree
Hide file tree
Showing 41 changed files with 580 additions and 466 deletions.
10 changes: 10 additions & 0 deletions docs/angular/api-angular/generators/move.md
Expand Up @@ -56,6 +56,16 @@ Type: `string`

The new import path to use in the `tsconfig.base.json`.

### skipFormat

Alias(es): skip-format

Default: `false`

Type: `boolean`

Skip formatting files.

### updateImportPath

Default: `true`
Expand Down
10 changes: 10 additions & 0 deletions docs/node/api-angular/generators/move.md
Expand Up @@ -56,6 +56,16 @@ Type: `string`

The new import path to use in the `tsconfig.base.json`.

### skipFormat

Alias(es): skip-format

Default: `false`

Type: `boolean`

Skip formatting files.

### updateImportPath

Default: `true`
Expand Down
10 changes: 10 additions & 0 deletions docs/react/api-angular/generators/move.md
Expand Up @@ -56,6 +56,16 @@ Type: `string`

The new import path to use in the `tsconfig.base.json`.

### skipFormat

Alias(es): skip-format

Default: `false`

Type: `boolean`

Skip formatting files.

### updateImportPath

Default: `true`
Expand Down
43 changes: 32 additions & 11 deletions packages/angular/src/generators/move/lib/update-module-name.spec.ts
Expand Up @@ -10,6 +10,30 @@ import { UnitTestRunner } from '../../../utils/test-runners';
describe('updateModuleName Rule', () => {
let tree: Tree;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

it('should handle nesting resulting in the same project name', async () => {
const updatedModulePath = '/libs/my/first/src/lib/my-first.module.ts';
await libraryGenerator(tree, {
name: 'my-first',
simpleModuleName: true,
});
const schema: Schema = {
projectName: 'my-first',
destination: 'my/first',
updateImportPath: true,
};
await moveGenerator(tree, schema);

updateModuleName(tree, { ...schema, destination: 'my/first' });

expect(tree.exists(updatedModulePath)).toBe(true);
const moduleFile = tree.read(updatedModulePath).toString('utf-8');
expect(moduleFile).toContain(`export class MyFirstModule { }`);
});

describe('move to subfolder', () => {
const updatedModulePath =
'/libs/shared/my-first/src/lib/shared-my-first.module.ts';
Expand All @@ -25,8 +49,6 @@ describe('updateModuleName Rule', () => {
};

beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();

await libraryGenerator(tree, {
name: 'my-first',
buildable: false,
Expand Down Expand Up @@ -86,7 +108,7 @@ describe('updateModuleName Rule', () => {
});

it('should rename the module files and update the module name', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

expect(tree.exists(updatedModulePath)).toBe(true);
expect(tree.exists(updatedModuleSpecPath)).toBe(true);
Expand All @@ -108,26 +130,27 @@ describe('updateModuleName Rule', () => {
});

it('should update any references to the module', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

const importerFile = tree.read(secondModulePath).toString('utf-8');
expect(importerFile).toContain(
`import { SharedMyFirstModule } from '@proj/shared/my-first';`
`import { SharedMyFirstModule } from '@proj/shared-my-first';`
);
expect(importerFile).toContain(
`export class MySecondModule extends SharedMyFirstModule {}`
);
});

it('should update the index.ts file which exports the module', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

const indexFile = tree.read(indexPath).toString('utf-8');
expect(indexFile).toContain(
`export * from './lib/shared-my-first.module';`
);
});
});

describe('rename', () => {
const schema: Schema = {
projectName: 'my-source',
Expand All @@ -142,8 +165,6 @@ describe('updateModuleName Rule', () => {
const importerPath = '/libs/my-importer/src/lib/my-importing-file.ts';

beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();

// fake a mid-move tree:
await libraryGenerator(tree, {
name: 'my-destination',
Expand Down Expand Up @@ -211,7 +232,7 @@ describe('updateModuleName Rule', () => {
});

it('should rename the module files and update the module name', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

expect(tree.exists(modulePath)).toBe(true);
expect(tree.exists(moduleSpecPath)).toBe(true);
Expand All @@ -233,7 +254,7 @@ describe('updateModuleName Rule', () => {
});

it('should update any references to the module', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

const importerFile = tree.read(importerPath).toString('utf-8');
expect(importerFile).toContain(
Expand All @@ -245,7 +266,7 @@ describe('updateModuleName Rule', () => {
});

it('should update the index.ts file which exports the module', async () => {
await updateModuleName(tree, schema);
updateModuleName(tree, schema);

const indexFile = tree.read(indexPath).toString('utf-8');
expect(indexFile).toContain(
Expand Down
17 changes: 11 additions & 6 deletions packages/angular/src/generators/move/lib/update-module-name.ts
Expand Up @@ -8,6 +8,7 @@ import {
import { getNewProjectName } from '@nrwl/workspace/src/generators/move/lib/utils';
import { join } from 'path';
import { Schema } from '../schema';

/**
* Updates the Angular module name (including the spec file and index.ts)
*
Expand All @@ -16,18 +17,18 @@ import { Schema } from '../schema';
*
* @param schema The options provided to the schematic
*/
export async function updateModuleName(
export function updateModuleName(
tree: Tree,
{ projectName, destination }: Schema
) {
): void {
const newProjectName = getNewProjectName(destination);

const project = readProjectConfiguration(tree, newProjectName);

if (project.projectType === 'application') {
// Expect the module to be something like 'app.module.ts' regardless of the folder name,
// Therefore, nothing to do.
return tree;
return;
}

const moduleName = {
Expand All @@ -53,7 +54,11 @@ export async function updateModuleName(
from: `${project.sourceRoot}/lib/${moduleFile.from}.spec.ts`,
to: `${project.sourceRoot}/lib/${moduleFile.to}.spec.ts`,
},
];
].filter((rename) => rename.from !== rename.to);

if (filesToRename.length === 0) {
return;
}

const replacements = [
{
Expand Down Expand Up @@ -84,8 +89,7 @@ export async function updateModuleName(
const skipFiles = [...filesToRename.map((file) => file.to), indexFile];

// Update any files which import the module

for (const [name, definition] of getProjects(tree)) {
for (const [, definition] of getProjects(tree)) {
visitNotIgnoredFiles(tree, definition.root, (file) => {
// skip files that were already modified

Expand All @@ -97,6 +101,7 @@ export async function updateModuleName(
});
}
}

function updateFileContent(
tree: Tree,
replacements: { regex: RegExp; replaceWith: string }[],
Expand Down
28 changes: 28 additions & 0 deletions packages/angular/src/generators/move/move.spec.ts
@@ -1,4 +1,5 @@
import { Tree } from '@nrwl/devkit';
import * as devkit from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { angularMoveGenerator } from './move';
import libraryGenerator from '../library/library';
Expand All @@ -21,6 +22,8 @@ describe('@nrwl/angular:move', () => {
skipFormat: false,
unitTestRunner: UnitTestRunner.Jest,
});

jest.clearAllMocks();
});

it('should move a project', async () => {
Expand All @@ -34,4 +37,29 @@ describe('@nrwl/angular:move', () => {
true
);
});

it('should format files', async () => {
jest.spyOn(devkit, 'formatFiles');

await angularMoveGenerator(tree, {
projectName: 'mylib',
destination: 'mynewlib',
updateImportPath: true,
});

expect(devkit.formatFiles).toHaveBeenCalled();
});

it('should not format files when --skipFormat=true', async () => {
jest.spyOn(devkit, 'formatFiles');

await angularMoveGenerator(tree, {
projectName: 'mylib',
destination: 'mynewlib',
updateImportPath: true,
skipFormat: true,
});

expect(devkit.formatFiles).not.toHaveBeenCalled();
});
});
14 changes: 10 additions & 4 deletions packages/angular/src/generators/move/move.ts
@@ -1,4 +1,4 @@
import { convertNxGenerator, Tree } from '@nrwl/devkit';
import { convertNxGenerator, formatFiles, Tree } from '@nrwl/devkit';
import { moveGenerator } from '@nrwl/workspace';
import { updateModuleName } from './lib/update-module-name';
import { Schema } from './schema';
Expand All @@ -10,10 +10,16 @@ import { Schema } from './schema';
* to the workspace, so it can't use the same tricks as the `@nrwl/workspace` rules
* to get the before and after names and paths.
*/
export async function angularMoveGenerator(
tree: Tree,
schema: Schema
): Promise<void> {
await moveGenerator(tree, { ...schema, skipFormat: true });
updateModuleName(tree, schema);

export async function angularMoveGenerator(tree: Tree, schema: Schema) {
await moveGenerator(tree, schema);
await updateModuleName(tree, schema);
if (!schema.skipFormat) {
await formatFiles(tree);
}
}

export const angularMoveSchematic = convertNxGenerator(angularMoveGenerator);
3 changes: 2 additions & 1 deletion packages/angular/src/generators/move/schema.d.ts
@@ -1,6 +1,7 @@
export interface Schema {
projectName: string;
destination: string;
importPath?: string;
updateImportPath: boolean;
importPath?: string;
skipFormat?: boolean;
}
6 changes: 6 additions & 0 deletions packages/angular/src/generators/move/schema.json
Expand Up @@ -33,6 +33,12 @@
"type": "boolean",
"description": "Update the import path to reflect the new location.",
"default": true
},
"skipFormat": {
"type": "boolean",
"aliases": ["skip-format"],
"description": "Skip formatting files.",
"default": false
}
},
"required": ["projectName", "destination"]
Expand Down
Expand Up @@ -65,17 +65,4 @@ describe('checkDestination', () => {
checkDestination(tree, schema, projectConfig);
}).not.toThrow();
});

it('should normalize the destination', async () => {
const schema: Schema = {
projectName: 'my-lib',
destination: '/my-other-lib//wibble',
importPath: undefined,
updateImportPath: true,
};

checkDestination(tree, schema, projectConfig);

expect(schema.destination).toBe('my-other-lib/wibble');
});
});
@@ -1,6 +1,6 @@
import { ProjectConfiguration, Tree } from '@nrwl/devkit';
import { Schema } from '../schema';
import { getDestination, normalizeSlashes } from './utils';
import { getDestination } from './utils';

/**
* Checks whether the destination folder is valid
Expand All @@ -26,8 +26,4 @@ export function checkDestination(
if (tree.children(destination).length > 0) {
throw new Error(`${INVALID_DESTINATION} - Path is not empty.`);
}

if (schema.destination.startsWith('/')) {
schema.destination = normalizeSlashes(schema.destination.substr(1));
}
}

0 comments on commit 64b560e

Please sign in to comment.