From 64b560e4b780b5d467a0d61e8d44b0c24a12aa53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Mon, 26 Jul 2021 12:26:28 +0100 Subject: [PATCH] fix(misc): handle moving to a subfolder which results in the same project name and normalize import path --- docs/angular/api-angular/generators/move.md | 10 + docs/node/api-angular/generators/move.md | 10 + docs/react/api-angular/generators/move.md | 10 + .../move/lib/update-module-name.spec.ts | 43 ++- .../generators/move/lib/update-module-name.ts | 17 +- .../angular/src/generators/move/move.spec.ts | 28 ++ packages/angular/src/generators/move/move.ts | 14 +- .../angular/src/generators/move/schema.d.ts | 3 +- .../angular/src/generators/move/schema.json | 6 + .../move/lib/check-destination.spec.ts | 13 - .../generators/move/lib/check-destination.ts | 6 +- .../lib/move-project-configuration.spec.ts | 35 +-- .../move/lib/move-project-configuration.ts | 17 +- .../generators/move/lib/move-project.spec.ts | 11 +- .../src/generators/move/lib/move-project.ts | 11 +- .../move/lib/normalize-schema.spec.ts | 78 +++++ .../generators/move/lib/normalize-schema.ts | 29 ++ .../move/lib/update-build-targets.spec.ts | 9 +- .../move/lib/update-build-targets.ts | 9 +- .../move/lib/update-cypress-json.spec.ts | 13 +- .../move/lib/update-cypress-json.ts | 18 +- .../move/lib/update-default-project.spec.ts | 11 +- .../move/lib/update-default-project.ts | 9 +- .../move/lib/update-eslintrc-json.spec.ts | 18 +- .../move/lib/update-eslintrc-json.ts | 17 +- .../lib/update-implicit-dependencies.spec.ts | 9 +- .../move/lib/update-implicit-dependencies.ts | 14 +- .../move/lib/update-imports.spec.ts | 283 ++++++++---------- .../src/generators/move/lib/update-imports.ts | 10 +- .../move/lib/update-jest-config.spec.ts | 56 ++-- .../generators/move/lib/update-jest-config.ts | 23 +- .../move/lib/update-package-json.spec.ts | 25 +- .../move/lib/update-package-json.ts | 25 +- .../lib/update-project-root-files.spec.ts | 12 +- .../move/lib/update-project-root-files.ts | 25 +- .../generators/move/lib/update-readme.spec.ts | 28 +- .../src/generators/move/lib/update-readme.ts | 18 +- .../move/lib/update-storybook-config.spec.ts | 33 +- .../move/lib/update-storybook-config.ts | 21 +- .../workspace/src/generators/move/move.ts | 13 +- .../workspace/src/generators/move/schema.d.ts | 6 + 41 files changed, 580 insertions(+), 466 deletions(-) create mode 100644 packages/workspace/src/generators/move/lib/normalize-schema.spec.ts create mode 100644 packages/workspace/src/generators/move/lib/normalize-schema.ts diff --git a/docs/angular/api-angular/generators/move.md b/docs/angular/api-angular/generators/move.md index d1130ec4fadf21..e4ffac9d21469c 100644 --- a/docs/angular/api-angular/generators/move.md +++ b/docs/angular/api-angular/generators/move.md @@ -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` diff --git a/docs/node/api-angular/generators/move.md b/docs/node/api-angular/generators/move.md index 68951f0cd66eb1..465bea4e13ad52 100644 --- a/docs/node/api-angular/generators/move.md +++ b/docs/node/api-angular/generators/move.md @@ -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` diff --git a/docs/react/api-angular/generators/move.md b/docs/react/api-angular/generators/move.md index 68951f0cd66eb1..465bea4e13ad52 100644 --- a/docs/react/api-angular/generators/move.md +++ b/docs/react/api-angular/generators/move.md @@ -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` diff --git a/packages/angular/src/generators/move/lib/update-module-name.spec.ts b/packages/angular/src/generators/move/lib/update-module-name.spec.ts index 0de5c16670a949..44216261e511f9 100644 --- a/packages/angular/src/generators/move/lib/update-module-name.spec.ts +++ b/packages/angular/src/generators/move/lib/update-module-name.spec.ts @@ -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'; @@ -25,8 +49,6 @@ describe('updateModuleName Rule', () => { }; beforeEach(async () => { - tree = createTreeWithEmptyWorkspace(); - await libraryGenerator(tree, { name: 'my-first', buildable: false, @@ -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); @@ -108,11 +130,11 @@ 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 {}` @@ -120,7 +142,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( @@ -128,6 +150,7 @@ describe('updateModuleName Rule', () => { ); }); }); + describe('rename', () => { const schema: Schema = { projectName: 'my-source', @@ -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', @@ -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); @@ -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( @@ -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( diff --git a/packages/angular/src/generators/move/lib/update-module-name.ts b/packages/angular/src/generators/move/lib/update-module-name.ts index b779ec5e65d1c1..1d2bb1e1559129 100644 --- a/packages/angular/src/generators/move/lib/update-module-name.ts +++ b/packages/angular/src/generators/move/lib/update-module-name.ts @@ -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) * @@ -16,10 +17,10 @@ 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); @@ -27,7 +28,7 @@ export async function updateModuleName( 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 = { @@ -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 = [ { @@ -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 @@ -97,6 +101,7 @@ export async function updateModuleName( }); } } + function updateFileContent( tree: Tree, replacements: { regex: RegExp; replaceWith: string }[], diff --git a/packages/angular/src/generators/move/move.spec.ts b/packages/angular/src/generators/move/move.spec.ts index afa07cee9369b4..9c14c8aef7a3a3 100644 --- a/packages/angular/src/generators/move/move.spec.ts +++ b/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'; @@ -21,6 +22,8 @@ describe('@nrwl/angular:move', () => { skipFormat: false, unitTestRunner: UnitTestRunner.Jest, }); + + jest.clearAllMocks(); }); it('should move a project', async () => { @@ -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(); + }); }); diff --git a/packages/angular/src/generators/move/move.ts b/packages/angular/src/generators/move/move.ts index 0d55dafc90831a..79c562edd4a8fb 100644 --- a/packages/angular/src/generators/move/move.ts +++ b/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'; @@ -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 { + 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); diff --git a/packages/angular/src/generators/move/schema.d.ts b/packages/angular/src/generators/move/schema.d.ts index 14f247d3b79807..424f3150b739a9 100644 --- a/packages/angular/src/generators/move/schema.d.ts +++ b/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; } diff --git a/packages/angular/src/generators/move/schema.json b/packages/angular/src/generators/move/schema.json index d3645e5090994e..9fa0ea99ebc41a 100644 --- a/packages/angular/src/generators/move/schema.json +++ b/packages/angular/src/generators/move/schema.json @@ -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"] diff --git a/packages/workspace/src/generators/move/lib/check-destination.spec.ts b/packages/workspace/src/generators/move/lib/check-destination.spec.ts index 71883c65e2b153..d2859bb19d176d 100644 --- a/packages/workspace/src/generators/move/lib/check-destination.spec.ts +++ b/packages/workspace/src/generators/move/lib/check-destination.spec.ts @@ -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'); - }); }); diff --git a/packages/workspace/src/generators/move/lib/check-destination.ts b/packages/workspace/src/generators/move/lib/check-destination.ts index 60c6f86d065dce..b2665bd79136e4 100644 --- a/packages/workspace/src/generators/move/lib/check-destination.ts +++ b/packages/workspace/src/generators/move/lib/check-destination.ts @@ -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 @@ -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)); - } } diff --git a/packages/workspace/src/generators/move/lib/move-project-configuration.spec.ts b/packages/workspace/src/generators/move/lib/move-project-configuration.spec.ts index 64d3e57208eada..3234ed2df10c75 100644 --- a/packages/workspace/src/generators/move/lib/move-project-configuration.spec.ts +++ b/packages/workspace/src/generators/move/lib/move-project-configuration.spec.ts @@ -1,24 +1,27 @@ +import type { Tree } from '@nrwl/devkit'; import { addProjectConfiguration, + ProjectConfiguration, readJson, readProjectConfiguration, - updateJson, } from '@nrwl/devkit'; -import type { Tree, NxJsonConfiguration } from '@nrwl/devkit'; -import type { Schema } from '../schema'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import type { NormalizedSchema } from '../schema'; import { moveProjectConfiguration } from './move-project-configuration'; describe('moveProjectConfiguration', () => { let tree: Tree; - let projectConfig; - let schema: Schema; + let projectConfig: ProjectConfiguration; + let schema: NormalizedSchema; + beforeEach(async () => { schema = { projectName: 'my-source', destination: 'subfolder/my-destination', - importPath: undefined, + importPath: '@proj/subfolder-my-destination', updateImportPath: true, + newProjectName: 'subfolder-my-destination', + relativeToRootDestination: 'apps/subfolder/my-destination', }; tree = createTreeWithEmptyWorkspace(); @@ -146,13 +149,13 @@ describe('moveProjectConfiguration', () => { projectConfig = readProjectConfiguration(tree, 'my-source'); }); + it('should rename the project', async () => { moveProjectConfiguration(tree, schema, projectConfig); expect(() => { readProjectConfiguration(tree, 'my-source'); }).toThrow(); - expect( readProjectConfiguration(tree, 'subfolder-my-destination') ).toBeDefined(); @@ -167,27 +170,13 @@ describe('moveProjectConfiguration', () => { ); expect(actualProject).toBeDefined(); expect(actualProject.root).toBe('apps/subfolder/my-destination'); - expect(actualProject.root).toBe('apps/subfolder/my-destination'); + expect(actualProject.sourceRoot).toBe('apps/subfolder/my-destination/src'); const similarProject = readProjectConfiguration(tree, 'my-source-e2e'); expect(similarProject).toBeDefined(); expect(similarProject.root).toBe('apps/my-source-e2e'); }); - it('honor custom workspace layouts', async () => { - updateJson(tree, 'nx.json', (json) => { - json.workspaceLayout = { appsDir: 'e2e', libsDir: 'packages' }; - return json; - }); - - moveProjectConfiguration(tree, schema, projectConfig); - - const project = readProjectConfiguration(tree, 'subfolder-my-destination'); - expect(project).toBeDefined(); - expect(project.root).toBe('e2e/subfolder/my-destination'); - expect(project.sourceRoot).toBe('e2e/subfolder/my-destination/src'); - }); - it('should update nx.json', () => { moveProjectConfiguration(tree, schema, projectConfig); @@ -195,10 +184,8 @@ describe('moveProjectConfiguration', () => { tree, 'subfolder-my-destination' ); - expect(actualProject.tags).toEqual(['type:ui']); expect(actualProject.implicitDependencies).toEqual(['my-other-lib']); - expect(readJson(tree, 'nx.json').projects['my-source']).not.toBeDefined(); }); }); diff --git a/packages/workspace/src/generators/move/lib/move-project-configuration.ts b/packages/workspace/src/generators/move/lib/move-project-configuration.ts index 6a63a741cfd538..7707b410aef589 100644 --- a/packages/workspace/src/generators/move/lib/move-project-configuration.ts +++ b/packages/workspace/src/generators/move/lib/move-project-configuration.ts @@ -1,24 +1,21 @@ import { addProjectConfiguration, - removeProjectConfiguration, NxJsonProjectConfiguration, ProjectConfiguration, + removeProjectConfiguration, Tree, } from '@nrwl/devkit'; - -import { Schema } from '../schema'; -import { getDestination, getNewProjectName } from './utils'; +import { NormalizedSchema } from '../schema'; export function moveProjectConfiguration( tree: Tree, - schema: Schema, + schema: NormalizedSchema, projectConfig: ProjectConfiguration & NxJsonProjectConfiguration ) { - let destination = getDestination(tree, schema, projectConfig); const projectString = JSON.stringify(projectConfig); const newProjectString = projectString.replace( new RegExp(projectConfig.root, 'g'), - destination + schema.relativeToRootDestination ); // rename @@ -28,9 +25,5 @@ export function moveProjectConfiguration( removeProjectConfiguration(tree, schema.projectName); // Create a new project with the root replaced - addProjectConfiguration( - tree, - getNewProjectName(schema.destination), - newProject - ); + addProjectConfiguration(tree, schema.newProjectName, newProject); } diff --git a/packages/workspace/src/generators/move/lib/move-project.spec.ts b/packages/workspace/src/generators/move/lib/move-project.spec.ts index 9215a04a9dee12..7a493cd74d22e0 100644 --- a/packages/workspace/src/generators/move/lib/move-project.spec.ts +++ b/packages/workspace/src/generators/move/lib/move-project.spec.ts @@ -4,9 +4,9 @@ import { Tree, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Schema } from '../schema'; -import { libraryGenerator } from '../../library/library'; import { moveProject } from '@nrwl/workspace/src/generators/move/lib/move-project'; +import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; describe('moveProject', () => { let tree: Tree; @@ -19,18 +19,19 @@ describe('moveProject', () => { }); it('should copy all files and delete the source folder', async () => { - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-lib', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; moveProject(tree, schema, projectConfig); const destinationChildren = tree.children('libs/my-destination'); expect(destinationChildren.length).toBeGreaterThan(0); - expect(tree.exists('libs/my-lib')).toBeFalsy(); expect(tree.children('libs')).not.toContain('my-lib'); }); diff --git a/packages/workspace/src/generators/move/lib/move-project.ts b/packages/workspace/src/generators/move/lib/move-project.ts index 27c49a60dc1984..9ac9aacc343922 100644 --- a/packages/workspace/src/generators/move/lib/move-project.ts +++ b/packages/workspace/src/generators/move/lib/move-project.ts @@ -1,7 +1,6 @@ import { ProjectConfiguration, Tree, visitNotIgnoredFiles } from '@nrwl/devkit'; -import { Schema } from '../schema'; -import { getDestination } from './utils'; import { join, relative } from 'path'; +import { NormalizedSchema } from '../schema'; /** * Moves a project to the given destination path @@ -10,15 +9,17 @@ import { join, relative } from 'path'; */ export function moveProject( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); visitNotIgnoredFiles(tree, project.root, (file) => { // This is a rename but Angular Devkit isn't capable of writing to a file after it's renamed so this is a workaround const content = tree.read(file); const relativeFromOriginalSource = relative(project.root, file); - const newFilePath = join(destination, relativeFromOriginalSource); + const newFilePath = join( + schema.relativeToRootDestination, + relativeFromOriginalSource + ); tree.write(newFilePath, content); tree.delete(file); }); diff --git a/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts b/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts new file mode 100644 index 00000000000000..ef66065e94b98e --- /dev/null +++ b/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts @@ -0,0 +1,78 @@ +import { + addProjectConfiguration, + NxJsonConfiguration, + ProjectConfiguration, + readProjectConfiguration, + Tree, + updateJson, +} from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { NormalizedSchema, Schema } from '../schema'; +import { normalizeSchema } from './normalize-schema'; + +describe('normalizeSchema', () => { + let tree: Tree; + let projectConfiguration: ProjectConfiguration; + const schema: Schema = { + destination: '/my/library', + projectName: 'my-library', + updateImportPath: true, + }; + + beforeEach(() => { + tree = createTreeWithEmptyWorkspace(); + + addProjectConfiguration(tree, schema.projectName, { + root: 'libs/my-library', + projectType: 'library', + targets: {}, + }); + + projectConfiguration = readProjectConfiguration(tree, schema.projectName); + }); + + it('should calculate importPath, projectName and relativeToRootDestination correctly', () => { + const expected: NormalizedSchema = { + destination: 'my/library', + importPath: '@proj/my-library', + newProjectName: 'my-library', + projectName: 'my-library', + relativeToRootDestination: 'libs/my/library', + updateImportPath: true, + }; + + const result = normalizeSchema(tree, schema, projectConfiguration); + + expect(result).toEqual(expected); + }); + + it('should use provided import path', () => { + const expected: NormalizedSchema = { + destination: 'my/library', + importPath: '@proj/my-awesome-library', + newProjectName: 'my-library', + projectName: 'my-library', + relativeToRootDestination: 'libs/my/library', + updateImportPath: true, + }; + + const result = normalizeSchema( + tree, + { ...schema, importPath: expected.importPath }, + projectConfiguration + ); + + expect(result).toEqual(expected); + }); + + it('should honor custom workspace layouts', async () => { + updateJson(tree, 'nx.json', (json) => { + json.workspaceLayout = { appsDir: 'apps', libsDir: 'packages' }; + return json; + }); + + const result = normalizeSchema(tree, schema, projectConfiguration); + + expect(result.relativeToRootDestination).toEqual('packages/my/library'); + }); +}); diff --git a/packages/workspace/src/generators/move/lib/normalize-schema.ts b/packages/workspace/src/generators/move/lib/normalize-schema.ts new file mode 100644 index 00000000000000..85be123df070f5 --- /dev/null +++ b/packages/workspace/src/generators/move/lib/normalize-schema.ts @@ -0,0 +1,29 @@ +import type { ProjectConfiguration, Tree } from '@nrwl/devkit'; +import { getWorkspaceLayout } from '@nrwl/devkit'; +import type { NormalizedSchema, Schema } from '../schema'; +import { getDestination, getNewProjectName, normalizeSlashes } from './utils'; + +export function normalizeSchema( + tree: Tree, + schema: Schema, + projectConfiguration: ProjectConfiguration +): NormalizedSchema { + const destination = schema.destination.startsWith('/') + ? normalizeSlashes(schema.destination.substr(1)) + : schema.destination; + const newProjectName = getNewProjectName(destination); + const { npmScope } = getWorkspaceLayout(tree); + + return { + ...schema, + destination, + importPath: + schema.importPath ?? normalizeSlashes(`@${npmScope}/${newProjectName}`), + newProjectName, + relativeToRootDestination: getDestination( + tree, + schema, + projectConfiguration + ), + }; +} diff --git a/packages/workspace/src/generators/move/lib/update-build-targets.spec.ts b/packages/workspace/src/generators/move/lib/update-build-targets.spec.ts index 6ab0a72e1acc52..8f0d8b127daeda 100644 --- a/packages/workspace/src/generators/move/lib/update-build-targets.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-build-targets.spec.ts @@ -1,23 +1,24 @@ -import { Schema } from '../schema'; import { addProjectConfiguration, readProjectConfiguration, Tree, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; - +import { NormalizedSchema } from '../schema'; import { updateBuildTargets } from './update-build-targets'; describe('updateBuildTargets', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; beforeEach(async () => { schema = { projectName: 'my-source', destination: 'subfolder/my-destination', - importPath: undefined, + importPath: '@proj/subfolder-my-destination', updateImportPath: true, + newProjectName: 'subfolder-my-destination', + relativeToRootDestination: 'libs/subfolder/my-destination', }; tree = createTreeWithEmptyWorkspace(); addProjectConfiguration(tree, 'my-source', { diff --git a/packages/workspace/src/generators/move/lib/update-build-targets.ts b/packages/workspace/src/generators/move/lib/update-build-targets.ts index 3163487b6d6a00..c6d7e66fddfc14 100644 --- a/packages/workspace/src/generators/move/lib/update-build-targets.ts +++ b/packages/workspace/src/generators/move/lib/update-build-targets.ts @@ -1,19 +1,16 @@ import { getWorkspacePath, Tree, updateJson } from '@nrwl/devkit'; -import { Schema } from '../schema'; -import { getNewProjectName } from './utils'; +import { NormalizedSchema } from '../schema'; /** * Update other references to the source project's targets */ -export function updateBuildTargets(tree: Tree, schema: Schema) { - const newProjectName = getNewProjectName(schema.destination); - +export function updateBuildTargets(tree: Tree, schema: NormalizedSchema) { updateJson(tree, getWorkspacePath(tree), (json) => { const strWorkspace = JSON.stringify(json); json = JSON.parse( strWorkspace.replace( new RegExp(`${schema.projectName}:`, 'g'), - `${newProjectName}:` + `${schema.newProjectName}:` ) ); return json; diff --git a/packages/workspace/src/generators/move/lib/update-cypress-json.spec.ts b/packages/workspace/src/generators/move/lib/update-cypress-json.spec.ts index b76ba60f7c4c37..db8a65b41fe082 100644 --- a/packages/workspace/src/generators/move/lib/update-cypress-json.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-cypress-json.spec.ts @@ -1,26 +1,28 @@ import { ProjectConfiguration, + readJson, readProjectConfiguration, Tree, - readJson, writeJson, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Schema } from '../schema'; -import { updateCypressJson } from './update-cypress-json'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateCypressJson } from './update-cypress-json'; describe('updateCypressJson', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; let projectConfig: ProjectConfiguration; beforeEach(async () => { schema = { projectName: 'my-lib', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; tree = createTreeWithEmptyWorkspace(); @@ -46,7 +48,6 @@ describe('updateCypressJson', () => { screenshotsFolder: '../../dist/cypress/libs/my-lib/screenshots', chromeWebSecurity: false, }; - writeJson(tree, '/libs/my-destination/cypress.json', cypressJson); updateCypressJson(tree, schema, projectConfig); diff --git a/packages/workspace/src/generators/move/lib/update-cypress-json.ts b/packages/workspace/src/generators/move/lib/update-cypress-json.ts index 46e09aabd4645c..36223242608980 100644 --- a/packages/workspace/src/generators/move/lib/update-cypress-json.ts +++ b/packages/workspace/src/generators/move/lib/update-cypress-json.ts @@ -1,8 +1,7 @@ import { Tree } from '@nrwl/devkit'; -import * as path from 'path'; -import { Schema } from '../schema'; -import { getDestination } from './utils'; import { ProjectConfiguration } from '@nrwl/tao/src/shared/workspace'; +import * as path from 'path'; +import { NormalizedSchema } from '../schema'; interface PartialCypressJson { videosFolder: string; @@ -18,12 +17,13 @@ interface PartialCypressJson { */ export function updateCypressJson( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); - - const cypressJsonPath = path.join(destination, 'cypress.json'); + const cypressJsonPath = path.join( + schema.relativeToRootDestination, + 'cypress.json' + ); if (!tree.exists(cypressJsonPath)) { // nothing to do @@ -35,11 +35,11 @@ export function updateCypressJson( ) as PartialCypressJson; cypressJson.videosFolder = cypressJson.videosFolder.replace( project.root, - destination + schema.relativeToRootDestination ); cypressJson.screenshotsFolder = cypressJson.screenshotsFolder.replace( project.root, - destination + schema.relativeToRootDestination ); tree.write(cypressJsonPath, JSON.stringify(cypressJson)); diff --git a/packages/workspace/src/generators/move/lib/update-default-project.spec.ts b/packages/workspace/src/generators/move/lib/update-default-project.spec.ts index af72f5d4504737..f2e57a2ed28f6a 100644 --- a/packages/workspace/src/generators/move/lib/update-default-project.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-default-project.spec.ts @@ -1,4 +1,3 @@ -import { Schema } from '@nrwl/workspace/src/generators/move/schema'; import { addProjectConfiguration, readWorkspaceConfiguration, @@ -6,7 +5,8 @@ import { updateWorkspaceConfiguration, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { updateDefaultProject } from '@nrwl/workspace/src/generators/move/lib/update-default-project'; +import { NormalizedSchema } from '../schema'; +import { updateDefaultProject } from './update-default-project'; describe('updateDefaultProject', () => { let tree: Tree; @@ -27,17 +27,18 @@ describe('updateDefaultProject', () => { }); it('should update the default project', async () => { - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'subfolder/my-destination', - importPath: undefined, + importPath: '@proj/subfolder-my-destination', updateImportPath: true, + newProjectName: 'subfolder-my-destination', + relativeToRootDestination: 'libs/subfolder/my-destination', }; updateDefaultProject(tree, schema); const { defaultProject } = readWorkspaceConfiguration(tree); - expect(defaultProject).toBe('subfolder-my-destination'); }); }); diff --git a/packages/workspace/src/generators/move/lib/update-default-project.ts b/packages/workspace/src/generators/move/lib/update-default-project.ts index 56d17e3488e21c..9a00bb327d5e0f 100644 --- a/packages/workspace/src/generators/move/lib/update-default-project.ts +++ b/packages/workspace/src/generators/move/lib/update-default-project.ts @@ -3,8 +3,7 @@ import { Tree, updateWorkspaceConfiguration, } from '@nrwl/devkit'; -import { Schema } from '../schema'; -import { getNewProjectName } from './utils'; +import { NormalizedSchema } from '../schema'; /** * Updates the project in the workspace file @@ -13,7 +12,7 @@ import { getNewProjectName } from './utils'; * - change the project name * - change target references */ -export function updateDefaultProject(tree: Tree, schema: Schema) { +export function updateDefaultProject(tree: Tree, schema: NormalizedSchema) { const workspaceConfiguration = readWorkspaceConfiguration(tree); // update default project (if necessary) @@ -21,9 +20,7 @@ export function updateDefaultProject(tree: Tree, schema: Schema) { workspaceConfiguration.defaultProject && workspaceConfiguration.defaultProject === schema.projectName ) { - workspaceConfiguration.defaultProject = getNewProjectName( - schema.destination - ); + workspaceConfiguration.defaultProject = schema.newProjectName; updateWorkspaceConfiguration(tree, workspaceConfiguration); } } diff --git a/packages/workspace/src/generators/move/lib/update-eslintrc-json.spec.ts b/packages/workspace/src/generators/move/lib/update-eslintrc-json.spec.ts index 2c7bb4b8bf7b16..2d3839053cb1a6 100644 --- a/packages/workspace/src/generators/move/lib/update-eslintrc-json.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-eslintrc-json.spec.ts @@ -5,23 +5,23 @@ import { updateJson, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; - import { Linter } from '../../../utils/lint'; - -import { Schema } from '../schema'; -import { updateEslintrcJson } from './update-eslintrc-json'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateEslintrcJson } from './update-eslintrc-json'; describe('updateEslint', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; beforeEach(async () => { schema = { projectName: 'my-lib', destination: 'shared/my-destination', - importPath: undefined, + importPath: '@proj/shared-my-destination', updateImportPath: true, + newProjectName: 'shared-my-destination', + relativeToRootDestination: 'libs/shared/my-destination', }; tree = createTreeWithEmptyWorkspace(); @@ -47,13 +47,11 @@ describe('updateEslint', () => { linter: Linter.EsLint, standaloneConfig: false, }); - // This step is usually handled elsewhere tree.rename( 'libs/my-lib/.eslintrc.json', 'libs/shared/my-destination/.eslintrc.json' ); - const projectConfig = readProjectConfiguration(tree, 'my-lib'); updateEslintrcJson(tree, schema, projectConfig); @@ -81,13 +79,11 @@ describe('updateEslint', () => { ]; return eslintRcJson; }); - // This step is usually handled elsewhere tree.rename( 'libs/my-lib/.eslintrc.json', 'libs/shared/my-destination/.eslintrc.json' ); - const projectConfig = readProjectConfiguration(tree, 'my-lib'); updateEslintrcJson(tree, schema, projectConfig); @@ -112,13 +108,11 @@ describe('updateEslint', () => { setParserOptionsProject: true, standaloneConfig: false, }); - // This step is usually handled elsewhere tree.rename( 'libs/my-lib/.eslintrc.json', 'libs/shared/my-destination/.eslintrc.json' ); - const projectConfig = readProjectConfiguration(tree, 'my-lib'); updateEslintrcJson(tree, schema, projectConfig); diff --git a/packages/workspace/src/generators/move/lib/update-eslintrc-json.ts b/packages/workspace/src/generators/move/lib/update-eslintrc-json.ts index 0ca3532273299b..0835474bb8f248 100644 --- a/packages/workspace/src/generators/move/lib/update-eslintrc-json.ts +++ b/packages/workspace/src/generators/move/lib/update-eslintrc-json.ts @@ -1,13 +1,11 @@ -import { join, relative } from 'path'; import { offsetFromRoot, ProjectConfiguration, Tree, updateJson, } from '@nrwl/devkit'; - -import { Schema } from '../schema'; -import { getDestination } from './utils'; +import { join } from 'path'; +import { NormalizedSchema } from '../schema'; interface PartialEsLintrcOverride { parserOptions?: { @@ -40,18 +38,17 @@ function offsetFilePath( */ export function updateEslintrcJson( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); - const eslintRcPath = join(destination, '.eslintrc.json'); + const eslintRcPath = join(schema.relativeToRootDestination, '.eslintrc.json'); if (!tree.exists(eslintRcPath)) { // no .eslintrc found. nothing to do return; } - const offset = offsetFromRoot(destination); + const offset = offsetFromRoot(schema.relativeToRootDestination); updateJson(tree, eslintRcPath, (eslintRcJson) => { if (typeof eslintRcJson.extends === 'string') { @@ -68,7 +65,9 @@ export function updateEslintrcJson( eslintRcJson.overrides?.forEach((o) => { if (o.parserOptions?.project) { - o.parserOptions.project = [`${destination}/tsconfig.*?.json`]; + o.parserOptions.project = [ + `${schema.relativeToRootDestination}/tsconfig.*?.json`, + ]; } }); diff --git a/packages/workspace/src/generators/move/lib/update-implicit-dependencies.spec.ts b/packages/workspace/src/generators/move/lib/update-implicit-dependencies.spec.ts index 0d25a2daed0864..3ea3d7650855df 100644 --- a/packages/workspace/src/generators/move/lib/update-implicit-dependencies.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-implicit-dependencies.spec.ts @@ -4,20 +4,21 @@ import { Tree, } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; - -import { Schema } from '../schema'; +import { NormalizedSchema } from '../schema'; import { updateImplicitDependencies } from './update-implicit-dependencies'; describe('updateImplicitDepenencies', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; beforeEach(async () => { schema = { projectName: 'my-lib', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; tree = createTreeWithEmptyWorkspace(); diff --git a/packages/workspace/src/generators/move/lib/update-implicit-dependencies.ts b/packages/workspace/src/generators/move/lib/update-implicit-dependencies.ts index 98cd0ecdf92fc2..408aa9eae6d2ec 100644 --- a/packages/workspace/src/generators/move/lib/update-implicit-dependencies.ts +++ b/packages/workspace/src/generators/move/lib/update-implicit-dependencies.ts @@ -1,22 +1,22 @@ +import type { NxJsonConfiguration, Tree } from '@nrwl/devkit'; import { updateJson } from '@nrwl/devkit'; -import type { Tree, NxJsonConfiguration } from '@nrwl/devkit'; -import type { Schema } from '../schema'; -import { getNewProjectName } from './utils'; +import type { NormalizedSchema } from '../schema'; /** * Updates the nx.json file by renaming the project * * @param schema The options provided to the schematic */ -export function updateImplicitDependencies(tree: Tree, schema: Schema) { +export function updateImplicitDependencies( + tree: Tree, + schema: NormalizedSchema +) { updateJson(tree, 'nx.json', (json) => { Object.values(json.projects).forEach((project) => { if (project.implicitDependencies) { const index = project.implicitDependencies.indexOf(schema.projectName); if (index !== -1) { - project.implicitDependencies[index] = getNewProjectName( - schema.destination - ); + project.implicitDependencies[index] = schema.newProjectName; } } }); diff --git a/packages/workspace/src/generators/move/lib/update-imports.spec.ts b/packages/workspace/src/generators/move/lib/update-imports.spec.ts index 2ab88de70ecca4..0c83169f06f3d1 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.spec.ts @@ -1,12 +1,12 @@ -import { readProjectConfiguration, Tree } from '@nrwl/devkit'; -import { Schema } from '../schema'; -import { updateImports } from './update-imports'; -import { libraryGenerator } from '../../library/library'; +import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateImports } from './update-imports'; describe('updateImports', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; beforeEach(async () => { tree = createTreeWithEmptyWorkspace(); @@ -14,8 +14,10 @@ describe('updateImports', () => { schema = { projectName: 'my-source', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; }); @@ -31,7 +33,6 @@ describe('updateImports', () => { name: 'my-source', standaloneConfig: false, }); - await libraryGenerator(tree, { name: 'my-importer', standaloneConfig: false, @@ -45,8 +46,8 @@ describe('updateImports', () => { export class MyExtendedClass extends MyClass {}; ` ); - const projectConfig = readProjectConfiguration(tree, 'my-source'); + updateImports(tree, schema, projectConfig); expect(tree.read(importerFilePath, 'utf-8')).toMatchSnapshot(); @@ -60,7 +61,6 @@ describe('updateImports', () => { it('should not update import paths when they contain a partial match', async () => { await libraryGenerator(tree, { name: 'table', standaloneConfig: false }); await libraryGenerator(tree, { name: 'tab', standaloneConfig: false }); - await libraryGenerator(tree, { name: 'my-importer', standaloneConfig: false, @@ -76,15 +76,17 @@ describe('updateImports', () => { export class MyTab extends Tab {}; ` ); - const projectConfig = readProjectConfiguration(tree, 'tab'); + updateImports( tree, { projectName: 'tab', destination: 'tabs', - importPath: undefined, + importPath: '@proj/tabs', updateImportPath: true, + newProjectName: 'tabs', + relativeToRootDestination: 'libs/tabs', }, projectConfig ); @@ -92,18 +94,15 @@ describe('updateImports', () => { expect(tree.read(importerFilePath, 'utf-8')).toContain( `import { Table } from '@proj/table';` ); - expect(tree.read(importerFilePath, 'utf-8')).toContain( `import { Tab } from '@proj/tabs';` ); - expect(tree.read(importerFilePath, 'utf-8')).toMatchSnapshot(); }); it('should correctly update deep imports', async () => { await libraryGenerator(tree, { name: 'table', standaloneConfig: false }); await libraryGenerator(tree, { name: 'tab', standaloneConfig: false }); - await libraryGenerator(tree, { name: 'my-importer', standaloneConfig: false, @@ -119,15 +118,17 @@ describe('updateImports', () => { export class MyTab extends Tab {}; ` ); - const projectConfig = readProjectConfiguration(tree, 'tab'); + updateImports( tree, { projectName: 'tab', destination: 'tabs', - importPath: undefined, + importPath: '@proj/tabs', updateImportPath: true, + newProjectName: 'tabs', + relativeToRootDestination: 'libs/tabs', }, projectConfig ); @@ -135,18 +136,15 @@ describe('updateImports', () => { expect(tree.read(importerFilePath, 'utf-8')).toContain( `import { Table } from '@proj/table/components';` ); - expect(tree.read(importerFilePath, 'utf-8')).toContain( `import { Tab } from '@proj/tabs/components';` ); - expect(tree.read(importerFilePath, 'utf-8')).toMatchSnapshot(); }); it('should update dynamic imports', async () => { await libraryGenerator(tree, { name: 'table', standaloneConfig: false }); await libraryGenerator(tree, { name: 'tab', standaloneConfig: false }); - await libraryGenerator(tree, { name: 'my-importer', standaloneConfig: false, @@ -161,15 +159,17 @@ describe('updateImports', () => { import('@proj/tab/components').then(m => m.Tab); ` ); - const projectConfig = readProjectConfiguration(tree, 'tab'); + updateImports( tree, { projectName: 'tab', destination: 'tabs', - importPath: undefined, + importPath: '@proj/tabs', updateImportPath: true, + newProjectName: 'tabs', + relativeToRootDestination: 'libs/tabs', }, projectConfig ); @@ -177,147 +177,124 @@ describe('updateImports', () => { expect(tree.read(importerFilePath, 'utf-8')).toContain( `import('@proj/table').then(m => m.Table);` ); - expect(tree.read(importerFilePath, 'utf-8')).toContain( `import('@proj/table/components').then(m => m.Table);` ); - expect(tree.read(importerFilePath, 'utf-8')).toContain( `import('@proj/tabs').then(m => m.Tab);` ); - expect(tree.read(importerFilePath, 'utf-8')).toContain( `import('@proj/tabs/components').then(m => m.Tab);` ); - expect(tree.read(importerFilePath, 'utf-8')).toMatchSnapshot(); }); - // - // it('should update require imports', async () => { - // tree = await runSchematic('lib', { name: 'table' }, tree); - // tree = await runSchematic('lib', { name: 'tab' }, tree); - // - // tree = await runSchematic('lib', { name: 'my-importer' }, tree); - // const importerFilePath = 'libs/my-importer/src/importer.ts'; - // tree.create( - // importerFilePath, - // ` - // require('@proj/table'); - // require('@proj/table/components'); - // require('@proj/tab'); - // require('@proj/tab/components'); - // ` - // ); - // - // tree = (await callRule( - // updateImports({ - // projectName: 'tab', - // destination: 'tabs', - // importPath: undefined, - // updateImportPath: true, - // }), - // tree - // )) as UnitTestTree; - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `require('@proj/table');` - // ); - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `require('@proj/table/components');` - // ); - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `require('@proj/tabs');` - // ); - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `require('@proj/tabs/components');` - // ); - // }); - // - // it('should not update project refs when --updateImportPath=false', async () => { - // // this is a bit of a cheat - we expect to run this rule on an intermediate state - // // tree where the workspace hasn't been updated yet, so just create libs representing - // // source and destination to make sure that the workspace has libraries with those names. - // tree = await runSchematic('lib', { name: 'my-destination' }, tree); - // tree = await runSchematic('lib', { name: 'my-source' }, tree); - // - // tree = await runSchematic('lib', { name: 'my-importer' }, tree); - // const importerFilePath = 'libs/my-importer/src/importer.ts'; - // tree.create( - // importerFilePath, - // ` - // import { MyClass } from '@proj/my-source'; - // - // export MyExtendedClass extends MyClass {}; - // ` - // ); - // - // schema.updateImportPath = false; - // tree = (await callRule(updateImports(schema), tree)) as UnitTestTree; - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `import { MyClass } from '@proj/my-source';` - // ); - // }); - // - // it('should update project refs to --importPath when provided', async () => { - // // this is a bit of a cheat - we expect to run this rule on an intermediate state - // // tree where the workspace hasn't been updated yet, so just create libs representing - // // source and destination to make sure that the workspace has libraries with those names. - // tree = await runSchematic('lib', { name: 'my-destination' }, tree); - // tree = await runSchematic('lib', { name: 'my-source' }, tree); - // - // tree = await runSchematic('lib', { name: 'my-importer' }, tree); - // const importerFilePath = 'libs/my-importer/src/importer.ts'; - // tree.create( - // importerFilePath, - // ` - // import { MyClass } from '@proj/my-source'; - // - // export class MyExtendedClass extends MyClass {}; - // ` - // ); - // - // schema.importPath = '@proj/wibble'; - // tree = (await callRule(updateImports(schema), tree)) as UnitTestTree; - // - // expect(tree.read(importerFilePath).toString()).toContain( - // `import { MyClass } from '${schema.importPath}';` - // ); - // }); - // - // it('should update project ref in the tsconfig file', async () => { - // tree = await runSchematic('lib', { name: 'my-source' }, tree); - // - // let tsConfig = readJsonInTree(tree, '/tsconfig.base.json'); - // expect(tsConfig.compilerOptions.paths).toEqual({ - // '@proj/my-source': ['libs/my-source/src/index.ts'], - // }); - // - // tree = (await callRule(updateImports(schema), tree)) as UnitTestTree; - // - // tsConfig = readJsonInTree(tree, '/tsconfig.base.json'); - // expect(tsConfig.compilerOptions.paths).toEqual({ - // '@proj/my-destination': ['libs/my-destination/src/index.ts'], - // }); - // }); - // - // it('should only update the project ref paths in the tsconfig file when --updateImportPath=false', async () => { - // tree = await runSchematic('lib', { name: 'my-source' }, tree); - // - // let tsConfig = readJsonInTree(tree, '/tsconfig.base.json'); - // expect(tsConfig.compilerOptions.paths).toEqual({ - // '@proj/my-source': ['libs/my-source/src/index.ts'], - // }); - // - // schema.updateImportPath = false; - // tree = (await callRule(updateImports(schema), tree)) as UnitTestTree; - // - // tsConfig = readJsonInTree(tree, '/tsconfig.base.json'); - // expect(tsConfig.compilerOptions.paths).toEqual({ - // '@proj/my-source': ['libs/my-destination/src/index.ts'], - // }); - // }); + + it('should update require imports', async () => { + await libraryGenerator(tree, { name: 'table', standaloneConfig: false }); + await libraryGenerator(tree, { name: 'tab', standaloneConfig: false }); + await libraryGenerator(tree, { + name: 'my-importer', + standaloneConfig: false, + }); + const importerFilePath = 'libs/my-importer/src/importer.ts'; + tree.write( + importerFilePath, + ` + require('@proj/table'); + require('@proj/table/components'); + require('@proj/tab'); + require('@proj/tab/components'); + ` + ); + const projectConfig = readProjectConfiguration(tree, 'tab'); + + updateImports( + tree, + { + projectName: 'tab', + destination: 'tabs', + importPath: '@proj/tabs', + updateImportPath: true, + newProjectName: 'tabs', + relativeToRootDestination: 'libs/tabs', + }, + projectConfig + ); + + expect(tree.read(importerFilePath).toString()).toContain( + `require('@proj/table');` + ); + expect(tree.read(importerFilePath).toString()).toContain( + `require('@proj/table/components');` + ); + expect(tree.read(importerFilePath).toString()).toContain( + `require('@proj/tabs');` + ); + expect(tree.read(importerFilePath).toString()).toContain( + `require('@proj/tabs/components');` + ); + }); + + it('should not update project refs when --updateImportPath=false', async () => { + // this is a bit of a cheat - we expect to run this rule on an intermediate state + // tree where the workspace hasn't been updated yet, so just create libs representing + // source and destination to make sure that the workspace has libraries with those names. + await libraryGenerator(tree, { + name: 'my-destination', + standaloneConfig: false, + }); + await libraryGenerator(tree, { + name: 'my-source', + standaloneConfig: false, + }); + await libraryGenerator(tree, { + name: 'my-importer', + standaloneConfig: false, + }); + const importerFilePath = 'libs/my-importer/src/importer.ts'; + tree.write( + importerFilePath, + `import { MyClass } from '@proj/my-source'; + +export MyExtendedClass extends MyClass {};` + ); + schema.updateImportPath = false; + const projectConfig = readProjectConfiguration(tree, 'my-source'); + + updateImports(tree, { ...schema, updateImportPath: false }, projectConfig); + + expect(tree.read(importerFilePath).toString()).toContain( + `import { MyClass } from '@proj/my-source';` + ); + }); + + it('should update project ref in the tsconfig file', async () => { + await libraryGenerator(tree, { + name: 'my-source', + standaloneConfig: false, + }); + const projectConfig = readProjectConfiguration(tree, 'my-source'); + + updateImports(tree, schema, projectConfig); + + const tsConfig = readJson(tree, '/tsconfig.base.json'); + expect(tsConfig.compilerOptions.paths).toEqual({ + '@proj/my-destination': ['libs/my-destination/src/index.ts'], + }); + }); + + it('should only update the project ref paths in the tsconfig file when --updateImportPath=false', async () => { + await libraryGenerator(tree, { + name: 'my-source', + standaloneConfig: false, + }); + const projectConfig = readProjectConfiguration(tree, 'my-source'); + + updateImports(tree, { ...schema, updateImportPath: false }, projectConfig); + + const tsConfig = readJson(tree, '/tsconfig.base.json'); + expect(tsConfig.compilerOptions.paths).toEqual({ + '@proj/my-source': ['libs/my-destination/src/index.ts'], + }); + }); }); diff --git a/packages/workspace/src/generators/move/lib/update-imports.ts b/packages/workspace/src/generators/move/lib/update-imports.ts index 4b235513eaa0f8..7b906f8601f6fa 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.ts @@ -9,9 +9,9 @@ import { visitNotIgnoredFiles, writeJson, } from '@nrwl/devkit'; -import { findNodes } from '../../../utilities/typescript/find-nodes'; import * as ts from 'typescript'; -import { Schema } from '../schema'; +import { findNodes } from '../../../utilities/typescript/find-nodes'; +import { NormalizedSchema } from '../schema'; import { normalizeSlashes } from './utils'; /** @@ -21,7 +21,7 @@ import { normalizeSlashes } from './utils'; */ export function updateImports( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { if (project.projectType === 'application') { @@ -52,9 +52,7 @@ export function updateImports( normalizeSlashes( `@${npmScope}/${project.root.substr(libsDir.length + 1)}` ), - to: - schema.importPath || - normalizeSlashes(`@${npmScope}/${schema.destination}`), + to: schema.importPath, }; if (schema.updateImportPath) { diff --git a/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts b/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts index a3e97c92b6cb4c..fe26d3da45bd9d 100644 --- a/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts @@ -1,9 +1,8 @@ import { readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; - -import { Schema } from '../schema'; -import { updateJestConfig } from './update-jest-config'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateJestConfig } from './update-jest-config'; describe('updateJestConfig', () => { let tree: Tree; @@ -18,15 +17,16 @@ describe('updateJestConfig', () => { standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; - updateJestConfig(tree, schema, projectConfig); + expect(() => updateJestConfig(tree, schema, projectConfig)).not.toThrow(); }); it('should update the name and coverage directory', async () => { @@ -40,21 +40,20 @@ describe('updateJestConfig', () => { ] };`; const jestConfigPath = '/libs/my-destination/jest.config.js'; - const rootJestConfigPath = '/jest.config.js'; - await libraryGenerator(tree, { name: 'my-source', standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); tree.write(jestConfigPath, jestConfig); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; updateJestConfig(tree, schema, projectConfig); @@ -65,7 +64,6 @@ describe('updateJestConfig', () => { expect(jestConfigAfter).toContain( `coverageDirectory: '../../coverage/libs/my-destination'` ); - expect(rootJestConfigAfter).toContain('getJestProjects()'); }); @@ -80,9 +78,7 @@ describe('updateJestConfig', () => { ] };`; const jestConfigPath = '/libs/other/test/dir/my-destination/jest.config.js'; - const rootJestConfigPath = '/jest.config.js'; - await libraryGenerator(tree, { name: 'some/test/dir/my-source', standaloneConfig: false, @@ -92,29 +88,27 @@ describe('updateJestConfig', () => { 'some-test-dir-my-source' ); tree.write(jestConfigPath, jestConfig); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'some-test-dir-my-source', destination: 'other/test/dir/my-destination', - importPath: undefined, + importPath: '@proj/other-test-dir-my-destination', updateImportPath: true, + newProjectName: 'other-test-dir-my-destination', + relativeToRootDestination: 'libs/other/test/dir/my-destination', }; updateJestConfig(tree, schema, projectConfig); - const jestConfigAfter = tree.read(jestConfigPath, 'utf-8'); const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8'); expect(jestConfigAfter).toContain(`name: 'other-test-dir-my-destination'`); expect(jestConfigAfter).toContain( `coverageDirectory: '../../coverage/libs/other/test/dir/my-destination'` ); - expect(rootJestConfigAfter).toContain('getJestProjects()'); }); it('updates the root config if not using `getJestProjects()`', async () => { const rootJestConfigPath = '/jest.config.js'; - await libraryGenerator(tree, { name: 'some/test/dir/my-source', standaloneConfig: false, @@ -130,11 +124,13 @@ describe('updateJestConfig', () => { tree, 'some-test-dir-my-source' ); - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'some-test-dir-my-source', destination: 'other/test/dir/my-destination', - importPath: undefined, + importPath: '@proj/other-test-dir-my-destination', updateImportPath: true, + newProjectName: 'other-test-dir-my-destination', + relativeToRootDestination: 'libs/other/test/dir/my-destination', }; updateJestConfig(tree, schema, projectConfig); @@ -150,7 +146,6 @@ describe('updateJestConfig', () => { it('updates the root config if `getJestProjects()` is used but old path exists', async () => { const rootJestConfigPath = '/jest.config.js'; - await libraryGenerator(tree, { name: 'some/test/dir/my-source', standaloneConfig: false, @@ -168,11 +163,13 @@ module.exports = { tree, 'some-test-dir-my-source' ); - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'some-test-dir-my-source', destination: 'other/test/dir/my-destination', - importPath: undefined, + importPath: '@proj/other-test-dir-my-destination', updateImportPath: true, + newProjectName: 'other-test-dir-my-destination', + relativeToRootDestination: 'libs/other/test/dir/my-destination', }; updateJestConfig(tree, schema, projectConfig); @@ -189,7 +186,6 @@ module.exports = { it('updates the root config if `getJestProjects()` is used with other projects in the array', async () => { const rootJestConfigPath = '/jest.config.js'; - await libraryGenerator(tree, { name: 'some/test/dir/my-source', standaloneConfig: false, @@ -207,11 +203,13 @@ module.exports = { tree, 'some-test-dir-my-source' ); - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'some-test-dir-my-source', destination: 'other/test/dir/my-destination', - importPath: undefined, + importPath: '@proj/other-test-dir-my-destination', updateImportPath: true, + newProjectName: 'other-test-dir-my-destination', + relativeToRootDestination: 'libs/other/test/dir/my-destination', }; updateJestConfig(tree, schema, projectConfig); diff --git a/packages/workspace/src/generators/move/lib/update-jest-config.ts b/packages/workspace/src/generators/move/lib/update-jest-config.ts index 30446512f496db..8a517e3d91b61c 100644 --- a/packages/workspace/src/generators/move/lib/update-jest-config.ts +++ b/packages/workspace/src/generators/move/lib/update-jest-config.ts @@ -1,9 +1,6 @@ -import { Tree, ProjectConfiguration } from '@nrwl/devkit'; - +import { ProjectConfiguration, Tree } from '@nrwl/devkit'; import * as path from 'path'; - -import { Schema } from '../schema'; -import { getDestination, getNewProjectName } from './utils'; +import { NormalizedSchema } from '../schema'; /** * Updates the project name and coverage folder in the jest.config.js if it exists @@ -14,13 +11,13 @@ import { getDestination, getNewProjectName } from './utils'; */ export function updateJestConfig( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); - const newProjectName = getNewProjectName(schema.destination); - - const jestConfigPath = path.join(destination, 'jest.config.js'); + const jestConfigPath = path.join( + schema.relativeToRootDestination, + 'jest.config.js' + ); if (tree.exists(jestConfigPath)) { const oldContent = tree.read(jestConfigPath, 'utf-8'); @@ -29,8 +26,8 @@ export function updateJestConfig( const findDir = new RegExp(project.root, 'g'); const newContent = oldContent - .replace(findName, `'${newProjectName}'`) - .replace(findDir, destination); + .replace(findName, `'${schema.newProjectName}'`) + .replace(findDir, schema.relativeToRootDestination); tree.write(jestConfigPath, newContent); } @@ -49,7 +46,7 @@ export function updateJestConfig( const newRootJestConfigContent = oldRootJestConfigContent.replace( findProject, - usingJestProjects ? `` : `'/${destination}'` + usingJestProjects ? `` : `'/${schema.relativeToRootDestination}'` ); tree.write(rootJestConfigPath, newRootJestConfigContent); diff --git a/packages/workspace/src/generators/move/lib/update-package-json.spec.ts b/packages/workspace/src/generators/move/lib/update-package-json.spec.ts index acceb8c3aa1fe9..2aab74d283d2ad 100644 --- a/packages/workspace/src/generators/move/lib/update-package-json.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-package-json.spec.ts @@ -1,36 +1,30 @@ -import { - ProjectConfiguration, - readProjectConfiguration, - Tree, - readJson, - writeJson, -} from '@nrwl/devkit'; +import { readJson, Tree, writeJson } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Schema } from '../schema'; -import { updatePackageJson } from './update-package-json'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updatePackageJson } from './update-package-json'; describe('updatePackageJson', () => { let tree: Tree; - let schema: Schema; - let projectConfig: ProjectConfiguration; + let schema: NormalizedSchema; beforeEach(async () => { schema = { projectName: 'my-lib', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; tree = createTreeWithEmptyWorkspace(); await libraryGenerator(tree, { name: 'my-lib', standaloneConfig: false }); - projectConfig = readProjectConfiguration(tree, 'my-lib'); }); it('should handle package.json not existing', async () => { expect(() => { - updatePackageJson(tree, schema, projectConfig); + updatePackageJson(tree, schema); }).not.toThrow(); }); @@ -38,10 +32,9 @@ describe('updatePackageJson', () => { const packageJson = { name: '@proj/my-lib', }; - writeJson(tree, '/libs/my-destination/package.json', packageJson); - updatePackageJson(tree, schema, projectConfig); + updatePackageJson(tree, schema); expect(readJson(tree, '/libs/my-destination/package.json')).toEqual({ ...packageJson, diff --git a/packages/workspace/src/generators/move/lib/update-package-json.ts b/packages/workspace/src/generators/move/lib/update-package-json.ts index 015cae7e426d88..6dd227294a4982 100644 --- a/packages/workspace/src/generators/move/lib/update-package-json.ts +++ b/packages/workspace/src/generators/move/lib/update-package-json.ts @@ -1,8 +1,6 @@ -import { Tree, getWorkspaceLayout } from '@nrwl/devkit'; +import { readJson, Tree } from '@nrwl/devkit'; import * as path from 'path'; -import { Schema } from '../schema'; -import { getDestination, normalizeSlashes } from './utils'; -import { ProjectConfiguration } from '@nrwl/tao/src/shared/workspace'; +import { NormalizedSchema } from '../schema'; interface PartialPackageJson { name: string; @@ -13,23 +11,18 @@ interface PartialPackageJson { * * @param schema The options provided to the schematic */ -export function updatePackageJson( - tree: Tree, - schema: Schema, - project: ProjectConfiguration -) { - const destination = getDestination(tree, schema, project); - const packageJsonPath = path.join(destination, 'package.json'); +export function updatePackageJson(tree: Tree, schema: NormalizedSchema) { + const packageJsonPath = path.join( + schema.relativeToRootDestination, + 'package.json' + ); if (!tree.exists(packageJsonPath)) { // nothing to do return; } - const { npmScope } = getWorkspaceLayout(tree); - const packageJson = JSON.parse( - tree.read(packageJsonPath).toString('utf-8') - ) as PartialPackageJson; - packageJson.name = normalizeSlashes(`@${npmScope}/${schema.destination}`); + const packageJson = readJson(tree, packageJsonPath) as PartialPackageJson; + packageJson.name = schema.importPath; tree.write(packageJsonPath, JSON.stringify(packageJson)); } diff --git a/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts b/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts index d8802e14e4a2c5..33b62fd6e5c7f6 100644 --- a/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts @@ -1,8 +1,8 @@ import { readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; -import { Schema } from '../schema'; -import { updateProjectRootFiles } from './update-project-root-files'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateProjectRootFiles } from './update-project-root-files'; describe('updateProjectRootFiles', () => { let tree: Tree; @@ -22,19 +22,19 @@ describe('updateProjectRootFiles', () => { ] };`; const testFilePath = '/libs/subfolder/my-destination/jest.config.js'; - await libraryGenerator(tree, { name: 'my-source', standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); tree.write(testFilePath, testFile); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'subfolder/my-destination', - importPath: undefined, + importPath: '@proj/subfolder-my-destination', updateImportPath: true, + newProjectName: 'subfolder-my-destination', + relativeToRootDestination: 'libs/subfolder/my-destination', }; updateProjectRootFiles(tree, schema, projectConfig); diff --git a/packages/workspace/src/generators/move/lib/update-project-root-files.ts b/packages/workspace/src/generators/move/lib/update-project-root-files.ts index 9bfcd8913793fd..fa076d271ce312 100644 --- a/packages/workspace/src/generators/move/lib/update-project-root-files.ts +++ b/packages/workspace/src/generators/move/lib/update-project-root-files.ts @@ -1,11 +1,8 @@ -import * as path from 'path'; - import { ProjectConfiguration, Tree } from '@nrwl/devkit'; - import { appRootPath } from '@nrwl/tao/src/utils/app-root'; -import { Schema } from '../schema'; -import { getDestination } from './utils'; +import * as path from 'path'; import { extname, join } from 'path'; +import { NormalizedSchema } from '../schema'; /** * Updates the files in the root of the project @@ -16,13 +13,14 @@ import { extname, join } from 'path'; */ export function updateProjectRootFiles( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); - const newRelativeRoot = path - .relative(path.join(appRootPath, destination), appRootPath) + .relative( + path.join(appRootPath, schema.relativeToRootDestination), + appRootPath + ) .split(path.sep) .join('/'); const oldRelativeRoot = path @@ -38,13 +36,16 @@ export function updateProjectRootFiles( const dots = /\./g; const regex = new RegExp(oldRelativeRoot.replace(dots, '\\.'), 'g'); - for (const file of tree.children(destination)) { + for (const file of tree.children(schema.relativeToRootDestination)) { if (!extname(file).startsWith('.js')) { continue; } - const oldContent = tree.read(join(destination, file), 'utf-8'); + const oldContent = tree.read( + join(schema.relativeToRootDestination, file), + 'utf-8' + ); const newContent = oldContent.replace(regex, newRelativeRoot); - tree.write(join(destination, file), newContent); + tree.write(join(schema.relativeToRootDestination, file), newContent); } } diff --git a/packages/workspace/src/generators/move/lib/update-readme.spec.ts b/packages/workspace/src/generators/move/lib/update-readme.spec.ts index 343a6c447601c1..7a17c7237e11b7 100644 --- a/packages/workspace/src/generators/move/lib/update-readme.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-readme.spec.ts @@ -1,22 +1,22 @@ -import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; +import { Tree } from '@nrwl/devkit'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; - -import { updateReadme } from './update-readme'; -import { Schema } from '../schema'; -import { libraryGenerator } from '../../library/library'; -import { getDestination } from './utils'; import { join } from 'path'; +import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateReadme } from './update-readme'; describe('updateReadme', () => { let tree: Tree; - let schema: Schema; + let schema: NormalizedSchema; beforeEach(async () => { schema = { projectName: 'my-lib', destination: 'shared/my-destination', - importPath: undefined, + importPath: '@proj/shared-my-destination', updateImportPath: true, + newProjectName: 'shared-my-destination', + relativeToRootDestination: 'libs/shared/my-destination', }; tree = createTreeWithEmptyWorkspace(); @@ -27,14 +27,11 @@ describe('updateReadme', () => { name: 'my-lib', standaloneConfig: false, }); - - const projectConfig = readProjectConfiguration(tree, 'my-lib'); - const destination = getDestination(tree, schema, projectConfig); - const readmePath = join(destination, 'README.md'); + const readmePath = join(schema.relativeToRootDestination, 'README.md'); tree.delete(readmePath); expect(() => { - updateReadme(tree, schema, projectConfig); + updateReadme(tree, schema); }).not.toThrow(); }); @@ -43,16 +40,13 @@ describe('updateReadme', () => { name: 'my-lib', standaloneConfig: false, }); - // This step is usually handled elsewhere tree.rename( 'libs/my-lib/README.md', 'libs/shared/my-destination/README.md' ); - const projectConfig = readProjectConfiguration(tree, 'my-lib'); - - updateReadme(tree, schema, projectConfig); + updateReadme(tree, schema); const content = tree .read('/libs/shared/my-destination/README.md') diff --git a/packages/workspace/src/generators/move/lib/update-readme.ts b/packages/workspace/src/generators/move/lib/update-readme.ts index 9f66ad3b6bf42e..ebc66f433a866e 100644 --- a/packages/workspace/src/generators/move/lib/update-readme.ts +++ b/packages/workspace/src/generators/move/lib/update-readme.ts @@ -1,29 +1,21 @@ +import { Tree } from '@nrwl/devkit'; import { join } from 'path'; -import { ProjectConfiguration, Tree } from '@nrwl/devkit'; - -import { Schema } from '../schema'; -import { getDestination, getNewProjectName } from './utils'; +import { NormalizedSchema } from '../schema'; /** * Update the README.md file of the project if it exists. * * @param schema The options provided to the schematic */ -export function updateReadme( - tree: Tree, - schema: Schema, - project: ProjectConfiguration -) { - const destination = getDestination(tree, schema, project); - const readmePath = join(destination, 'README.md'); +export function updateReadme(tree: Tree, schema: NormalizedSchema) { + const readmePath = join(schema.relativeToRootDestination, 'README.md'); if (!tree.exists(readmePath)) { // no README found. nothing to do return; } - const newProjectName = getNewProjectName(schema.destination); const findName = new RegExp(`${schema.projectName}`, 'g'); const oldContent = tree.read(readmePath, 'utf-8'); - const newContent = oldContent.replace(findName, newProjectName); + const newContent = oldContent.replace(findName, schema.newProjectName); tree.write(readmePath, newContent); } diff --git a/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts b/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts index 35f801f443369b..17f3a2af6dc5f3 100644 --- a/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts @@ -1,8 +1,8 @@ import { readProjectConfiguration, Tree } from '@nrwl/devkit'; -import { Schema } from '../schema'; -import { updateStorybookConfig } from './update-storybook-config'; import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { libraryGenerator } from '../../library/library'; +import { NormalizedSchema } from '../schema'; +import { updateStorybookConfig } from './update-storybook-config'; describe('updateStorybookConfig', () => { let tree: Tree; @@ -17,15 +17,18 @@ describe('updateStorybookConfig', () => { standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'my-destination', - importPath: undefined, + importPath: '@proj/my-destination', updateImportPath: true, + newProjectName: 'my-destination', + relativeToRootDestination: 'libs/my-destination', }; - updateStorybookConfig(tree, schema, projectConfig); + expect(() => + updateStorybookConfig(tree, schema, projectConfig) + ).not.toThrow(); }); it('should update the import path for main.js', async () => { @@ -33,22 +36,21 @@ describe('updateStorybookConfig', () => { const rootMain = require('../../../.storybook/main'); module.exports = rootMain; `; - const storybookMainPath = '/libs/namespace/my-destination/.storybook/main.js'; - await libraryGenerator(tree, { name: 'my-source', standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); tree.write(storybookMainPath, storybookMain); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'namespace/my-destination', - importPath: undefined, + importPath: '@proj/namespace-my-destination', updateImportPath: true, + newProjectName: 'namespace-my-destination', + relativeToRootDestination: 'libs/namespace/my-destination', }; updateStorybookConfig(tree, schema, projectConfig); @@ -63,22 +65,21 @@ describe('updateStorybookConfig', () => { const storybookWebpackConfig = ` const rootWebpackConfig = require('../../../.storybook/webpack.config'); `; - const storybookWebpackConfigPath = '/libs/namespace/my-destination/.storybook/webpack.config.js'; - await libraryGenerator(tree, { name: 'my-source', standaloneConfig: false, }); const projectConfig = readProjectConfiguration(tree, 'my-source'); tree.write(storybookWebpackConfigPath, storybookWebpackConfig); - - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'namespace/my-destination', - importPath: undefined, + importPath: '@proj/namespace-my-destination', updateImportPath: true, + newProjectName: 'namespace-my-destination', + relativeToRootDestination: 'libs/namespace/my-destination', }; updateStorybookConfig(tree, schema, projectConfig); diff --git a/packages/workspace/src/generators/move/lib/update-storybook-config.ts b/packages/workspace/src/generators/move/lib/update-storybook-config.ts index 27911462cecc99..c4f0459386ac33 100644 --- a/packages/workspace/src/generators/move/lib/update-storybook-config.ts +++ b/packages/workspace/src/generators/move/lib/update-storybook-config.ts @@ -1,11 +1,8 @@ import { ProjectConfiguration, Tree } from '@nrwl/devkit'; - -import * as path from 'path'; - import { appRootPath } from '@nrwl/tao/src/utils/app-root'; -import { Schema } from '../schema'; -import { getDestination } from './utils'; +import * as path from 'path'; import { join } from 'path'; +import { NormalizedSchema } from '../schema'; /** * Updates relative path to root storybook config for `main.js` & `webpack.config.js` @@ -14,21 +11,25 @@ import { join } from 'path'; */ export function updateStorybookConfig( tree: Tree, - schema: Schema, + schema: NormalizedSchema, project: ProjectConfiguration ) { - const destination = getDestination(tree, schema, project); - const oldRelativeRoot = path .relative(path.join(appRootPath, `${project.root}/.storybook`), appRootPath) .split(path.sep) .join('/'); const newRelativeRoot = path - .relative(path.join(appRootPath, `${destination}/.storybook`), appRootPath) + .relative( + path.join(appRootPath, `${schema.relativeToRootDestination}/.storybook`), + appRootPath + ) .split(path.sep) .join('/'); - const storybookDir = path.join(destination, '.storybook'); + const storybookDir = path.join( + schema.relativeToRootDestination, + '.storybook' + ); if (!storybookDir) { return; diff --git a/packages/workspace/src/generators/move/move.ts b/packages/workspace/src/generators/move/move.ts index 166174becfbe58..a8132849843909 100644 --- a/packages/workspace/src/generators/move/move.ts +++ b/packages/workspace/src/generators/move/move.ts @@ -20,10 +20,13 @@ import { moveProjectConfiguration } from './lib/move-project-configuration'; import { updateBuildTargets } from './lib/update-build-targets'; import { updateReadme } from './lib/update-readme'; import { updatePackageJson } from './lib/update-package-json'; +import { normalizeSchema } from './lib/normalize-schema'; + +export async function moveGenerator(tree: Tree, rawSchema: Schema) { + const projectConfig = readProjectConfiguration(tree, rawSchema.projectName); + checkDestination(tree, rawSchema, projectConfig); + const schema = normalizeSchema(tree, rawSchema, projectConfig); -export async function moveGenerator(tree: Tree, schema: Schema) { - const projectConfig = readProjectConfiguration(tree, schema.projectName); - checkDestination(tree, schema, projectConfig); moveProjectConfiguration(tree, schema, projectConfig); moveProject(tree, schema, projectConfig); // we MUST move the project first, if we don't we get a "This should never happen" error 🤦‍♀️ updateImports(tree, schema, projectConfig); @@ -32,8 +35,8 @@ export async function moveGenerator(tree: Tree, schema: Schema) { updateJestConfig(tree, schema, projectConfig); updateStorybookConfig(tree, schema, projectConfig); updateEslintrcJson(tree, schema, projectConfig); - updateReadme(tree, schema, projectConfig); - updatePackageJson(tree, schema, projectConfig); + updateReadme(tree, schema); + updatePackageJson(tree, schema); updateBuildTargets(tree, schema); updateDefaultProject(tree, schema); updateImplicitDependencies(tree, schema); diff --git a/packages/workspace/src/generators/move/schema.d.ts b/packages/workspace/src/generators/move/schema.d.ts index d5410c04ffa808..53a360d1709dd3 100644 --- a/packages/workspace/src/generators/move/schema.d.ts +++ b/packages/workspace/src/generators/move/schema.d.ts @@ -5,3 +5,9 @@ export interface Schema { updateImportPath: boolean; skipFormat?: boolean; } + +export interface NormalizedSchema extends Schema { + importPath: string; + newProjectName: string; + relativeToRootDestination: string; +}