From 3a4b967cd885b72987f789265d76df638fac975b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leosvel=20P=C3=A9rez=20Espinosa?= Date: Tue, 27 Jun 2023 12:28:07 +0100 Subject: [PATCH] fix(misc): fix misc issues with move generators --- .../angular/src/generators/move/lib/index.ts | 4 + .../generators/move/lib/normalize-schema.ts | 15 ++ .../move/lib/update-module-name.spec.ts | 54 +++++-- .../generators/move/lib/update-module-name.ts | 17 +-- .../generators/move/lib/update-ng-package.ts | 12 +- .../move/lib/update-secondary-entry-points.ts | 71 +++++++++ .../angular/src/generators/move/move.spec.ts | 23 +++ packages/angular/src/generators/move/move.ts | 19 ++- .../angular/src/generators/move/schema.d.ts | 5 + .../generators/utils/get-new-project-name.ts | 11 +- .../move/lib/normalize-schema.spec.ts | 19 +++ .../generators/move/lib/normalize-schema.ts | 13 +- .../move/lib/update-imports.spec.ts | 38 ++++- .../src/generators/move/lib/update-imports.ts | 141 +++++++++++------- .../src/generators/move/lib/utils.ts | 25 +++- 15 files changed, 360 insertions(+), 107 deletions(-) create mode 100644 packages/angular/src/generators/move/lib/index.ts create mode 100644 packages/angular/src/generators/move/lib/normalize-schema.ts create mode 100644 packages/angular/src/generators/move/lib/update-secondary-entry-points.ts diff --git a/packages/angular/src/generators/move/lib/index.ts b/packages/angular/src/generators/move/lib/index.ts new file mode 100644 index 0000000000000..0fcaada668fc2 --- /dev/null +++ b/packages/angular/src/generators/move/lib/index.ts @@ -0,0 +1,4 @@ +export * from './normalize-schema'; +export * from './update-module-name'; +export * from './update-ng-package'; +export * from './update-secondary-entry-points'; diff --git a/packages/angular/src/generators/move/lib/normalize-schema.ts b/packages/angular/src/generators/move/lib/normalize-schema.ts new file mode 100644 index 0000000000000..ce2afdd6d49b2 --- /dev/null +++ b/packages/angular/src/generators/move/lib/normalize-schema.ts @@ -0,0 +1,15 @@ +import type { Tree } from '@nx/devkit'; +import { readProjectConfiguration } from '@nx/devkit'; +import type { NormalizedSchema, Schema } from '../schema'; +import { getNewProjectName } from '../../utils/get-new-project-name'; + +export function normalizeSchema(tree: Tree, schema: Schema): NormalizedSchema { + const newProjectName = getNewProjectName(schema.destination); + const { root } = readProjectConfiguration(tree, schema.projectName); + + return { + ...schema, + newProjectName, + oldProjectRoot: root, + }; +} 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 8b5f0c977307c..fc8148e892037 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 @@ -4,7 +4,7 @@ import { Linter } from '@nx/linter'; import { moveGenerator } from '@nx/workspace/generators'; import { UnitTestRunner } from '../../../utils/test-runners'; import { generateTestLibrary } from '../../utils/testing'; -import { Schema } from '../schema'; +import { NormalizedSchema } from '../schema'; import { updateModuleName } from './update-module-name'; describe('updateModuleName Rule', () => { @@ -20,17 +20,19 @@ describe('updateModuleName Rule', () => { name: 'my-first', simpleName: true, }); - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-first', destination: 'my/first', updateImportPath: true, + newProjectName: 'my-first', + oldProjectRoot: 'libs/my-first', }; await moveGenerator(tree, schema); updateModuleName(tree, { ...schema, destination: 'my/first' }); expect(tree.exists(updatedModulePath)).toBe(true); - const moduleFile = tree.read(updatedModulePath).toString('utf-8'); + const moduleFile = tree.read(updatedModulePath, 'utf-8'); expect(moduleFile).toContain(`export class MyFirstModule {}`); }); @@ -42,10 +44,12 @@ describe('updateModuleName Rule', () => { const indexPath = '/libs/shared/my-first/src/index.ts'; const secondModulePath = '/libs/my-second/src/lib/my-second.module.ts'; - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-first', destination: 'shared/my-first', updateImportPath: true, + newProjectName: 'shared-my-first', + oldProjectRoot: 'libs/my-first', }; beforeEach(async () => { @@ -111,10 +115,10 @@ describe('updateModuleName Rule', () => { expect(tree.exists(updatedModulePath)).toBe(true); expect(tree.exists(updatedModuleSpecPath)).toBe(true); - const moduleFile = tree.read(updatedModulePath).toString('utf-8'); + const moduleFile = tree.read(updatedModulePath, 'utf-8'); expect(moduleFile).toContain(`export class SharedMyFirstModule {}`); - const moduleSpecFile = tree.read(updatedModuleSpecPath).toString('utf-8'); + const moduleSpecFile = tree.read(updatedModuleSpecPath, 'utf-8'); expect(moduleSpecFile).toContain( `import { SharedMyFirstModule } from './shared-my-first.module';` ); @@ -130,7 +134,7 @@ describe('updateModuleName Rule', () => { it('should update any references to the module', async () => { updateModuleName(tree, schema); - const importerFile = tree.read(secondModulePath).toString('utf-8'); + const importerFile = tree.read(secondModulePath, 'utf-8'); expect(importerFile).toContain( `import { SharedMyFirstModule } from '@proj/shared/my-first';` ); @@ -142,7 +146,7 @@ describe('updateModuleName Rule', () => { it('should update the index.ts file which exports the module', async () => { updateModuleName(tree, schema); - const indexFile = tree.read(indexPath).toString('utf-8'); + const indexFile = tree.read(indexPath, 'utf-8'); expect(indexFile).toContain( `export * from './lib/shared-my-first.module';` ); @@ -150,10 +154,12 @@ describe('updateModuleName Rule', () => { }); describe('rename', () => { - const schema: Schema = { + const schema: NormalizedSchema = { projectName: 'my-source', destination: 'my-destination', updateImportPath: true, + newProjectName: 'my-destination', + oldProjectRoot: 'libs/my-source', }; const modulePath = '/libs/my-destination/src/lib/my-destination.module.ts'; @@ -233,10 +239,10 @@ describe('updateModuleName Rule', () => { expect(tree.exists(modulePath)).toBe(true); expect(tree.exists(moduleSpecPath)).toBe(true); - const moduleFile = tree.read(modulePath).toString('utf-8'); + const moduleFile = tree.read(modulePath, 'utf-8'); expect(moduleFile).toContain(`export class MyDestinationModule {}`); - const moduleSpecFile = tree.read(moduleSpecPath).toString('utf-8'); + const moduleSpecFile = tree.read(moduleSpecPath, 'utf-8'); expect(moduleSpecFile).toContain( `import { MyDestinationModule } from './my-destination.module';` ); @@ -252,7 +258,7 @@ describe('updateModuleName Rule', () => { it('should update any references to the module', async () => { updateModuleName(tree, schema); - const importerFile = tree.read(importerPath).toString('utf-8'); + const importerFile = tree.read(importerPath, 'utf-8'); expect(importerFile).toContain( `import { MyDestinationModule } from '@proj/my-destination';` ); @@ -264,10 +270,32 @@ describe('updateModuleName Rule', () => { it('should update the index.ts file which exports the module', async () => { updateModuleName(tree, schema); - const indexFile = tree.read(indexPath).toString('utf-8'); + const indexFile = tree.read(indexPath, 'utf-8'); expect(indexFile).toContain( `export * from './lib/my-destination.module';` ); }); + + it('should not rename unrelated symbols with similar name in different projects', async () => { + // create different project whose main module name starts with the same + // name of the project we're moving + await generateTestLibrary(tree, { + name: 'my-source-demo', + buildable: false, + linter: Linter.EsLint, + publishable: false, + simpleName: true, + skipFormat: false, + unitTestRunner: UnitTestRunner.Jest, + }); + + updateModuleName(tree, schema); + + const moduleFile = tree.read( + '/libs/my-source-demo/src/lib/my-source-demo.module.ts', + 'utf-8' + ); + expect(moduleFile).toContain(`export class MySourceDemoModule {}`); + }); }); }); 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 902b1dc06123a..1359273ab653c 100644 --- a/packages/angular/src/generators/move/lib/update-module-name.ts +++ b/packages/angular/src/generators/move/lib/update-module-name.ts @@ -1,13 +1,12 @@ import { getProjects, + joinPathFragments, names, readProjectConfiguration, Tree, visitNotIgnoredFiles, } from '@nx/devkit'; -import { getNewProjectName } from '../../utils/get-new-project-name'; -import { join } from 'path'; -import { Schema } from '../schema'; +import type { NormalizedSchema } from '../schema'; /** * Updates the Angular module name (including the spec file and index.ts) @@ -19,10 +18,8 @@ import { Schema } from '../schema'; */ export function updateModuleName( tree: Tree, - { projectName, destination }: Schema + { projectName: oldProjectName, newProjectName }: NormalizedSchema ): void { - const newProjectName = getNewProjectName(destination); - const project = readProjectConfiguration(tree, newProjectName); if (project.projectType === 'application') { @@ -32,14 +29,14 @@ export function updateModuleName( } const moduleName = { - from: names(projectName).className, - to: names(newProjectName).className, + from: `${names(oldProjectName).className}Module`, + to: `${names(newProjectName).className}Module`, }; const findModuleName = new RegExp(`\\b${moduleName.from}`, 'g'); const moduleFile = { - from: `${projectName}.module`, + from: `${oldProjectName}.module`, to: `${newProjectName}.module`, }; @@ -81,7 +78,7 @@ export function updateModuleName( }); // update index file - const indexFile = join(project.sourceRoot, 'index.ts'); + const indexFile = joinPathFragments(project.sourceRoot, 'index.ts'); if (tree.exists(indexFile)) { updateFileContent(tree, replacements, indexFile); } diff --git a/packages/angular/src/generators/move/lib/update-ng-package.ts b/packages/angular/src/generators/move/lib/update-ng-package.ts index 39223a1edaf98..c7c87b55b2966 100644 --- a/packages/angular/src/generators/move/lib/update-ng-package.ts +++ b/packages/angular/src/generators/move/lib/update-ng-package.ts @@ -6,13 +6,11 @@ import { updateJson, workspaceRoot, } from '@nx/devkit'; -import { getNewProjectName } from '../../utils/get-new-project-name'; import { join, relative } from 'path'; -import { Schema } from '../schema'; +import type { NormalizedSchema } from '../schema'; -export function updateNgPackage(tree: Tree, schema: Schema): void { - const newProjectName = getNewProjectName(schema.destination); - const project = readProjectConfiguration(tree, newProjectName); +export function updateNgPackage(tree: Tree, schema: NormalizedSchema): void { + const project = readProjectConfiguration(tree, schema.newProjectName); if (project.projectType === 'application') { return; @@ -29,13 +27,13 @@ export function updateNgPackage(tree: Tree, schema: Schema): void { const outputs = getOutputsForTargetAndConfiguration( { target: { - project: newProjectName, + project: schema.newProjectName, target: 'build', }, overrides: {}, }, { - name: newProjectName, + name: schema.newProjectName, type: 'lib', data: { root: project.root, diff --git a/packages/angular/src/generators/move/lib/update-secondary-entry-points.ts b/packages/angular/src/generators/move/lib/update-secondary-entry-points.ts new file mode 100644 index 0000000000000..e20474049e32d --- /dev/null +++ b/packages/angular/src/generators/move/lib/update-secondary-entry-points.ts @@ -0,0 +1,71 @@ +import type { Tree } from '@nx/devkit'; +import { + joinPathFragments, + normalizePath, + readProjectConfiguration, + visitNotIgnoredFiles, +} from '@nx/devkit'; +import { basename, dirname } from 'path'; +import type { NormalizedSchema } from '../schema'; + +const libraryExecutors = [ + '@angular-devkit/build-angular:ng-packagr', + '@nx/angular:ng-packagr-lite', + '@nx/angular:package', + // TODO(v17): remove when @nrwl/* scope is removed + '@nrwl/angular:ng-packagr-lite', + '@nrwl/angular:package', +]; + +export function updateSecondaryEntryPoints( + tree: Tree, + schema: NormalizedSchema +): void { + const project = readProjectConfiguration(tree, schema.newProjectName); + + if (project.projectType !== 'library') { + return; + } + + if ( + !Object.values(project.targets ?? {}).some((target) => + libraryExecutors.includes(target.executor) + ) + ) { + return; + } + + visitNotIgnoredFiles(tree, project.root, (filePath) => { + if ( + basename(filePath) !== 'ng-package.json' || + normalizePath(filePath) === + joinPathFragments(project.root, 'ng-package.json') + ) { + return; + } + + updateReadme( + tree, + dirname(filePath), + schema.projectName, + schema.newProjectName + ); + }); +} + +function updateReadme( + tree: Tree, + dir: string, + oldProjectName: string, + newProjectName: string +) { + const readmePath = joinPathFragments(dir, 'README.md'); + if (!tree.exists(readmePath)) { + return; + } + + const findName = new RegExp(`${oldProjectName}`, 'g'); + const oldContent = tree.read(readmePath, 'utf-8'); + const newContent = oldContent.replace(findName, newProjectName); + tree.write(readmePath, newContent); +} diff --git a/packages/angular/src/generators/move/move.spec.ts b/packages/angular/src/generators/move/move.spec.ts index ffb74dbc35960..de9857a5dd6e2 100644 --- a/packages/angular/src/generators/move/move.spec.ts +++ b/packages/angular/src/generators/move/move.spec.ts @@ -3,6 +3,7 @@ import { readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/linter'; import { UnitTestRunner } from '../../utils/test-runners'; +import librarySecondaryEntryPointGenerator from '../library-secondary-entry-point/library-secondary-entry-point'; import { generateTestLibrary } from '../utils/testing'; import { angularMoveGenerator } from './move'; @@ -50,6 +51,28 @@ describe('@nx/angular:move', () => { expect(ngPackageJson.dest).toEqual('../../dist/libs/mynewlib2'); }); + it('should update secondary entry points readme file', async () => { + await generateTestLibrary(tree, { name: 'mylib2', buildable: true }); + await librarySecondaryEntryPointGenerator(tree, { + library: 'mylib2', + name: 'testing', + }); + + await angularMoveGenerator(tree, { + projectName: 'mylib2', + destination: 'mynewlib2', + updateImportPath: true, + }); + + const readme = tree.read('libs/mynewlib2/testing/README.md', 'utf-8'); + expect(readme).toMatchInlineSnapshot(` + "# @proj/mynewlib2/testing + + Secondary entry point of \`@proj/mynewlib2\`. It can be used by importing from \`@proj/mynewlib2/testing\`. + " + `); + }); + it('should format files', async () => { jest.spyOn(devkit, 'formatFiles'); diff --git a/packages/angular/src/generators/move/move.ts b/packages/angular/src/generators/move/move.ts index 530ba72fece44..b5f77840c8d7c 100644 --- a/packages/angular/src/generators/move/move.ts +++ b/packages/angular/src/generators/move/move.ts @@ -1,8 +1,12 @@ import { formatFiles, Tree } from '@nx/devkit'; import { moveGenerator } from '@nx/workspace/generators'; -import { updateModuleName } from './lib/update-module-name'; -import { updateNgPackage } from './lib/update-ng-package'; -import { Schema } from './schema'; +import { + normalizeSchema, + updateModuleName, + updateNgPackage, + updateSecondaryEntryPoints, +} from './lib'; +import type { Schema } from './schema'; /** * Moves an Angular lib/app to another folder (and renames it in the process) @@ -15,11 +19,14 @@ export async function angularMoveGenerator( tree: Tree, schema: Schema ): Promise { + const normalizedSchema = normalizeSchema(tree, schema); + await moveGenerator(tree, { ...schema, skipFormat: true }); - updateModuleName(tree, schema); - updateNgPackage(tree, schema); + updateModuleName(tree, normalizedSchema); + updateNgPackage(tree, normalizedSchema); + updateSecondaryEntryPoints(tree, normalizedSchema); - if (!schema.skipFormat) { + if (!normalizedSchema.skipFormat) { await formatFiles(tree); } } diff --git a/packages/angular/src/generators/move/schema.d.ts b/packages/angular/src/generators/move/schema.d.ts index 424f3150b739a..8aa957be35039 100644 --- a/packages/angular/src/generators/move/schema.d.ts +++ b/packages/angular/src/generators/move/schema.d.ts @@ -5,3 +5,8 @@ export interface Schema { importPath?: string; skipFormat?: boolean; } + +export interface NormalizedSchema extends Schema { + oldProjectRoot: string; + newProjectName: string; +} diff --git a/packages/angular/src/generators/utils/get-new-project-name.ts b/packages/angular/src/generators/utils/get-new-project-name.ts index 904aba10a236f..5b015c4f4750f 100644 --- a/packages/angular/src/generators/utils/get-new-project-name.ts +++ b/packages/angular/src/generators/utils/get-new-project-name.ts @@ -1,8 +1,15 @@ +import { normalizePath } from '@nx/devkit'; + /** - * Replaces slashes with dashes + * Joins path segments replacing slashes with dashes * * @param path */ export function getNewProjectName(path: string): string { - return path.replace(/\//g, '-'); + // strip leading '/' or './' or '../' and trailing '/' and replaces '/' with '-' + return normalizePath(path) + .replace(/(^\.{0,2}\/|\.{1,2}\/|\/$)/g, '') + .split('/') + .filter((x) => !!x) + .join('-'); } diff --git a/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts b/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts index d5209d38524e7..fc5a3ba0df1c8 100644 --- a/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts +++ b/packages/workspace/src/generators/move/lib/normalize-schema.spec.ts @@ -46,6 +46,25 @@ describe('normalizeSchema', () => { expect(result).toEqual(expected); }); + it('should normalize destination and derive projectName 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, destination: './my/library' }, + projectConfiguration + ); + + expect(result).toEqual(expected); + }); + it('should use provided import path', () => { const expected: NormalizedSchema = { destination: 'my/library', diff --git a/packages/workspace/src/generators/move/lib/normalize-schema.ts b/packages/workspace/src/generators/move/lib/normalize-schema.ts index e7309ded09259..dbf892d21d5a3 100644 --- a/packages/workspace/src/generators/move/lib/normalize-schema.ts +++ b/packages/workspace/src/generators/move/lib/normalize-schema.ts @@ -1,6 +1,10 @@ import { ProjectConfiguration, Tree } from '@nx/devkit'; import type { NormalizedSchema, Schema } from '../schema'; -import { getDestination, getNewProjectName, normalizeSlashes } from './utils'; +import { + getDestination, + getNewProjectName, + normalizePathSlashes, +} from './utils'; import { getImportPath } from '../../../utilities/get-import-path'; export function normalizeSchema( @@ -8,9 +12,7 @@ export function normalizeSchema( schema: Schema, projectConfiguration: ProjectConfiguration ): NormalizedSchema { - const destination = schema.destination.startsWith('/') - ? normalizeSlashes(schema.destination.slice(1)) - : schema.destination; + const destination = normalizePathSlashes(schema.destination); const newProjectName = schema.newProjectName ?? getNewProjectName(destination); @@ -18,7 +20,8 @@ export function normalizeSchema( ...schema, destination, importPath: - schema.importPath ?? normalizeSlashes(getImportPath(tree, destination)), + schema.importPath ?? + normalizePathSlashes(getImportPath(tree, destination)), newProjectName, relativeToRootDestination: getDestination( tree, 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 02a0765bbb5b3..c199a257db773 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.spec.ts @@ -1,4 +1,9 @@ -import { readJson, readProjectConfiguration, Tree } from '@nx/devkit'; +import { + readJson, + readProjectConfiguration, + Tree, + updateJson, +} from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Schema } from '../schema'; import { updateImports } from './update-imports'; @@ -292,6 +297,37 @@ export MyExtendedClass extends MyClass {};` }); }); + it('should update project ref in the root tsconfig.base.json for secondary entry points', async () => { + await libraryGenerator(tree, { + name: 'my-source', + }); + updateJson(tree, '/tsconfig.base.json', (json) => { + json.compilerOptions.paths['@proj/my-source/testing'] = [ + 'libs/my-source/testing/src/index.ts', + ]; + json.compilerOptions.paths['@proj/different-alias'] = [ + 'libs/my-source/some-path/src/index.ts', + ]; + return json; + }); + const projectConfig = readProjectConfiguration(tree, 'my-source'); + + updateImports( + tree, + normalizeSchema(tree, schema, projectConfig), + projectConfig + ); + + const tsConfig = readJson(tree, '/tsconfig.base.json'); + expect(tsConfig.compilerOptions.paths).toEqual({ + '@proj/my-destination': ['libs/my-destination/src/index.ts'], + '@proj/my-destination/testing': [ + 'libs/my-destination/testing/src/index.ts', + ], + '@proj/different-alias': ['libs/my-destination/some-path/src/index.ts'], + }); + }); + it('should update project ref of a project not under libs in the root tsconfig.base.json', async () => { tree.delete('libs'); await libraryGenerator(tree, { diff --git a/packages/workspace/src/generators/move/lib/update-imports.ts b/packages/workspace/src/generators/move/lib/update-imports.ts index 882594a24ab0d..10d28006d1f44 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.ts @@ -17,7 +17,7 @@ import { findNodes, } from '../../../utilities/ts-config'; import { NormalizedSchema } from '../schema'; -import { normalizeSlashes } from './utils'; +import { normalizePathSlashes } from './utils'; import { relative } from 'path'; import { ensureTypescript } from '../../../utilities/typescript'; import { getImportPath } from '../../../utilities/get-import-path'; @@ -39,88 +39,119 @@ export function updateImports( return; } - const { npmScope, libsDir } = getWorkspaceLayout(tree); + const { libsDir } = getWorkspaceLayout(tree); const projects = getProjects(tree); // use the source root to find the from location // this attempts to account for libs that have been created with --importPath const tsConfigPath = getRootTsConfigPathInTree(tree); let tsConfig: any; - let fromPath: string; + let mainEntryPointImportPath: string; + let secondaryEntryPointImportPaths: string[]; if (tree.exists(tsConfigPath)) { tsConfig = readJson(tree, tsConfigPath); + const sourceRoot = + project.sourceRoot ?? joinPathFragments(project.root, 'src'); - fromPath = Object.keys(tsConfig.compilerOptions.paths).find((path) => + mainEntryPointImportPath = Object.keys( + tsConfig.compilerOptions?.paths ?? {} + ).find((path) => tsConfig.compilerOptions.paths[path].some((x) => - x.startsWith(project.sourceRoot) + x.startsWith(ensureTrailingSlash(sourceRoot)) + ) + ); + secondaryEntryPointImportPaths = Object.keys( + tsConfig.compilerOptions?.paths ?? {} + ).filter((path) => + tsConfig.compilerOptions.paths[path].some( + (x) => + x.startsWith(ensureTrailingSlash(project.root)) && + !x.startsWith(ensureTrailingSlash(sourceRoot)) ) ); } - const projectRef = { - from: - fromPath || - normalizeSlashes( - getImportPath( - tree, - project.root.slice(libsDir.length).replace(/^\/|\\/, '') - ) - ), - to: schema.importPath, - }; - - if (schema.updateImportPath) { - const replaceProjectRef = new RegExp(projectRef.from, 'g'); - - for (const [name, definition] of Array.from(projects.entries())) { - if (name === schema.projectName) { - continue; - } + mainEntryPointImportPath ??= normalizePathSlashes( + getImportPath( + tree, + project.root.slice(libsDir.length).replace(/^\/|\\/, '') + ) + ); - visitNotIgnoredFiles(tree, definition.root, (file) => { - const contents = tree.read(file, 'utf-8'); - replaceProjectRef.lastIndex = 0; - if (!replaceProjectRef.test(contents)) { - return; + const projectRefs = [ + { + from: mainEntryPointImportPath, + to: schema.importPath, + }, + ...secondaryEntryPointImportPaths.map((p) => ({ + from: p, + // if the import path doesn't start with the main entry point import path, + // it's a custom import path we don't know how to update the name, we keep + // it as-is, but we'll update the path it points to + to: p.startsWith(mainEntryPointImportPath) + ? p.replace(mainEntryPointImportPath, schema.importPath) + : null, + })), + ]; + + for (const projectRef of projectRefs) { + if (schema.updateImportPath && projectRef.to) { + const replaceProjectRef = new RegExp(projectRef.from, 'g'); + + for (const [name, definition] of Array.from(projects.entries())) { + if (name === schema.projectName) { + continue; } - updateImportPaths(tree, file, projectRef.from, projectRef.to); - }); + visitNotIgnoredFiles(tree, definition.root, (file) => { + const contents = tree.read(file, 'utf-8'); + replaceProjectRef.lastIndex = 0; + if (!replaceProjectRef.test(contents)) { + return; + } + + updateImportPaths(tree, file, projectRef.from, projectRef.to); + }); + } } - } - const projectRoot = { - from: project.root, - to: schema.relativeToRootDestination, - }; - - if (tsConfig) { - const path = tsConfig.compilerOptions.paths[projectRef.from] as string[]; - if (!path) { - throw new Error( - [ - `unable to find "${projectRef.from}" in`, - `${tsConfigPath} compilerOptions.paths`, - ].join(' ') + const projectRoot = { + from: project.root, + to: schema.relativeToRootDestination, + }; + + if (tsConfig) { + const path = tsConfig.compilerOptions.paths[projectRef.from] as string[]; + if (!path) { + throw new Error( + [ + `unable to find "${projectRef.from}" in`, + `${tsConfigPath} compilerOptions.paths`, + ].join(' ') + ); + } + const updatedPath = path.map((x) => + joinPathFragments(projectRoot.to, relative(projectRoot.from, x)) ); - } - const updatedPath = path.map((x) => - joinPathFragments(projectRoot.to, relative(projectRoot.from, x)) - ); - if (schema.updateImportPath) { - tsConfig.compilerOptions.paths[projectRef.to] = updatedPath; - if (projectRef.from !== projectRef.to) { - delete tsConfig.compilerOptions.paths[projectRef.from]; + if (schema.updateImportPath && projectRef.to) { + tsConfig.compilerOptions.paths[projectRef.to] = updatedPath; + if (projectRef.from !== projectRef.to) { + delete tsConfig.compilerOptions.paths[projectRef.from]; + } + } else { + tsConfig.compilerOptions.paths[projectRef.from] = updatedPath; } - } else { - tsConfig.compilerOptions.paths[projectRef.from] = updatedPath; } writeJson(tree, tsConfigPath, tsConfig); } } +function ensureTrailingSlash(path: string): string { + return path.endsWith('/') ? path : `${path}/`; +} + /** * Changes imports in a file from one import to another */ diff --git a/packages/workspace/src/generators/move/lib/utils.ts b/packages/workspace/src/generators/move/lib/utils.ts index 284c04e1b8edd..294e509c7237c 100644 --- a/packages/workspace/src/generators/move/lib/utils.ts +++ b/packages/workspace/src/generators/move/lib/utils.ts @@ -1,10 +1,10 @@ import { getWorkspaceLayout, joinPathFragments, + normalizePath, ProjectConfiguration, Tree, } from '@nx/devkit'; - import { Schema } from '../schema'; /** @@ -35,12 +35,17 @@ export function getDestination( } /** - * Replaces slashes with dashes + * Joins path segments replacing slashes with dashes * * @param path */ export function getNewProjectName(path: string): string { - return path.replace(/\//g, '-'); + // strip leading '/' or './' or '../' and trailing '/' and replaces '/' with '-' + return normalizePath(path) + .replace(/(^\.{0,2}\/|\.{1,2}\/|\/$)/g, '') + .split('/') + .filter((x) => !!x) + .join('-'); } /** @@ -48,9 +53,13 @@ export function getNewProjectName(path: string): string { * * @param input */ -export function normalizeSlashes(input: string): string { - return input - .split('/') - .filter((x) => !!x) - .join('/'); +export function normalizePathSlashes(input: string): string { + return ( + normalizePath(input) + // strip leading ./ or / + .replace(/^\.?\//, '') + .split('/') + .filter((x) => !!x) + .join('/') + ); }