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 09b8c6f256fc1..1ec416eec5d05 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,13 @@ import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import { libraryGenerator } from '../../library/library'; -import { NormalizedSchema } from '../schema'; +import { Schema } from '../schema'; import { updateImports } from './update-imports'; +import { normalizeSchema } from './normalize-schema'; describe('updateImports', () => { let tree: Tree; - let schema: NormalizedSchema; + let schema: Schema; beforeEach(async () => { tree = createTreeWithEmptyV1Workspace(); @@ -14,10 +15,7 @@ describe('updateImports', () => { schema = { projectName: 'my-source', destination: 'my-destination', - importPath: '@proj/my-destination', updateImportPath: true, - newProjectName: 'my-destination', - relativeToRootDestination: 'libs/my-destination', }; }); @@ -48,7 +46,11 @@ describe('updateImports', () => { ); const projectConfig = readProjectConfiguration(tree, 'my-source'); - updateImports(tree, schema, projectConfig); + updateImports( + tree, + normalizeSchema(tree, schema, projectConfig), + projectConfig + ); expect(tree.read(importerFilePath, 'utf-8')).toMatchSnapshot(); }); @@ -261,7 +263,18 @@ export MyExtendedClass extends MyClass {};` schema.updateImportPath = false; const projectConfig = readProjectConfiguration(tree, 'my-source'); - updateImports(tree, { ...schema, updateImportPath: false }, projectConfig); + updateImports( + tree, + normalizeSchema( + tree, + { + ...schema, + updateImportPath: false, + }, + projectConfig + ), + projectConfig + ); expect(tree.read(importerFilePath).toString()).toContain( `import { MyClass } from '@proj/my-source';` @@ -275,7 +288,11 @@ export MyExtendedClass extends MyClass {};` }); const projectConfig = readProjectConfiguration(tree, 'my-source'); - updateImports(tree, schema, projectConfig); + updateImports( + tree, + normalizeSchema(tree, schema, projectConfig), + projectConfig + ); const tsConfig = readJson(tree, '/tsconfig.base.json'); expect(tsConfig.compilerOptions.paths).toEqual({ @@ -283,6 +300,26 @@ export MyExtendedClass extends MyClass {};` }); }); + it('should update project ref of a project not under libs in the root tsconfig.base.json', async () => { + tree.delete('libs'); + await libraryGenerator(tree, { + name: 'my-source', + standaloneConfig: false, + }); + 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': ['my-destination/src/index.ts'], + }); + }); + it('should update project ref in the root tsconfig.json when no tsconfig.base.json', async () => { tree.rename('tsconfig.base.json', 'tsconfig.json'); await libraryGenerator(tree, { @@ -291,7 +328,11 @@ export MyExtendedClass extends MyClass {};` }); const projectConfig = readProjectConfiguration(tree, 'my-source'); - updateImports(tree, schema, projectConfig); + updateImports( + tree, + normalizeSchema(tree, schema, projectConfig), + projectConfig + ); const tsConfig = readJson(tree, '/tsconfig.json'); expect(tsConfig.compilerOptions.paths).toEqual({ @@ -306,7 +347,19 @@ export MyExtendedClass extends MyClass {};` }); const projectConfig = readProjectConfiguration(tree, 'my-source'); - updateImports(tree, { ...schema, updateImportPath: false }, projectConfig); + updateImports( + tree, + normalizeSchema( + tree, + { + ...schema, + updateImportPath: false, + }, + projectConfig + ), + + projectConfig + ); const tsConfig = readJson(tree, '/tsconfig.base.json'); expect(tsConfig.compilerOptions.paths).toEqual({ diff --git a/packages/workspace/src/generators/move/lib/update-imports.ts b/packages/workspace/src/generators/move/lib/update-imports.ts index c4ba29ffa4479..eb935048ef082 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.ts @@ -3,6 +3,7 @@ import { ChangeType, getProjects, getWorkspaceLayout, + joinPathFragments, ProjectConfiguration, StringChange, Tree, @@ -15,6 +16,7 @@ import { getRootTsConfigPathInTree } from '../../../utilities/typescript'; import { findNodes } from 'nx/src/utils/typescript'; import { NormalizedSchema } from '../schema'; import { normalizeSlashes } from './utils'; +import { relative } from 'path'; /** * Updates all the imports in the workspace and modifies the tsconfig appropriately. @@ -81,8 +83,8 @@ export function updateImports( } const projectRoot = { - from: project.root.slice(libsDir.length).replace(/^\/|\\/, ''), - to: schema.destination, + from: project.root, + to: schema.relativeToRootDestination, }; if (tsConfig) { @@ -96,7 +98,7 @@ export function updateImports( ); } const updatedPath = path.map((x) => - x.replace(new RegExp(projectRoot.from, 'g'), projectRoot.to) + joinPathFragments(projectRoot.to, relative(projectRoot.from, x)) ); if (schema.updateImportPath) { diff --git a/packages/workspace/src/generators/remove/lib/update-tsconfig.spec.ts b/packages/workspace/src/generators/remove/lib/update-tsconfig.spec.ts index b71b4721143ee..d74e8930ffbfc 100644 --- a/packages/workspace/src/generators/remove/lib/update-tsconfig.spec.ts +++ b/packages/workspace/src/generators/remove/lib/update-tsconfig.spec.ts @@ -1,16 +1,28 @@ -import { readJson, readProjectConfiguration, Tree } from '@nrwl/devkit'; -import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; +import { + ProjectGraph, + readJson, + readProjectConfiguration, + Tree, +} from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; import { Schema } from '../schema'; import { updateTsconfig } from './update-tsconfig'; import { libraryGenerator } from '../../library/library'; +let graph: ProjectGraph; +jest.mock('@nrwl/devkit', () => { + return { + ...jest.requireActual('@nrwl/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(() => graph), + }; +}); describe('updateTsconfig', () => { let tree: Tree; let schema: Schema; let schemaWithImportPath: Schema; beforeEach(async () => { - tree = createTreeWithEmptyV1Workspace(); + tree = createTreeWithEmptyWorkspace(); schema = { projectName: 'my-lib', @@ -31,9 +43,47 @@ describe('updateTsconfig', () => { name: 'my-lib', standaloneConfig: false, }); - const project = readProjectConfiguration(tree, 'my-lib'); - updateTsconfig(tree, schema, project); + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schema); + + const tsConfig = readJson(tree, '/tsconfig.base.json'); + expect(tsConfig.compilerOptions.paths).toEqual({}); + }); + + it('should delete project ref not under libs from the root tsconfig.base.json', async () => { + tree.delete('libs'); + await libraryGenerator(tree, { + name: 'my-lib', + standaloneConfig: false, + }); + + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schema); const tsConfig = readJson(tree, '/tsconfig.base.json'); expect(tsConfig.compilerOptions.paths).toEqual({}); @@ -45,9 +95,21 @@ describe('updateTsconfig', () => { standaloneConfig: false, importPath: '@proj/whatever-name', }); - const project = readProjectConfiguration(tree, 'my-lib'); - updateTsconfig(tree, schemaWithImportPath, project); + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schemaWithImportPath); const tsConfig = readJson(tree, '/tsconfig.base.json'); expect(tsConfig.compilerOptions.paths).toEqual({}); @@ -59,9 +121,21 @@ describe('updateTsconfig', () => { name: 'my-lib', standaloneConfig: false, }); - const project = readProjectConfiguration(tree, 'my-lib'); - updateTsconfig(tree, schema, project); + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schema); const tsConfig = readJson(tree, '/tsconfig.json'); expect(tsConfig.compilerOptions.paths).toEqual({}); @@ -74,11 +148,64 @@ describe('updateTsconfig', () => { standaloneConfig: false, importPath: '@proj/whatever-name', }); - const project = readProjectConfiguration(tree, 'my-lib'); - updateTsconfig(tree, schemaWithImportPath, project); + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schemaWithImportPath); const tsConfig = readJson(tree, '/tsconfig.json'); expect(tsConfig.compilerOptions.paths).toEqual({}); }); + + it('should not delete importPaths of nested projects from tsconfig.base.json', async () => { + await libraryGenerator(tree, { + name: 'my-lib', + standaloneConfig: false, + importPath: '@proj/whatever-name', + }); + await libraryGenerator(tree, { + name: 'nested-lib', + directory: 'libs/my-lib', + standaloneConfig: false, + importPath: '@proj/nested/whatever-name', + }); + + graph = { + nodes: { + 'my-lib': { + name: 'my-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib').root, + }, + }, + 'my-lib-nested-lib': { + name: 'my-lib-nested-lib', + type: 'lib', + data: { + root: readProjectConfiguration(tree, 'my-lib-nested-lib').root, + }, + }, + }, + dependencies: {}, + }; + + await updateTsconfig(tree, schemaWithImportPath); + + const tsConfig = readJson(tree, '/tsconfig.base.json'); + expect(tsConfig.compilerOptions.paths).toEqual({ + '@proj/nested/whatever-name': ['libs/my-lib/nested-lib/src/index.ts'], + }); + }); }); diff --git a/packages/workspace/src/generators/remove/lib/update-tsconfig.ts b/packages/workspace/src/generators/remove/lib/update-tsconfig.ts index a5a2c633b6e63..1d3e16c0086b7 100644 --- a/packages/workspace/src/generators/remove/lib/update-tsconfig.ts +++ b/packages/workspace/src/generators/remove/lib/update-tsconfig.ts @@ -1,38 +1,41 @@ import { - getWorkspaceLayout, - ProjectConfiguration, + createProjectGraphAsync, + normalizePath, + ProjectGraph, Tree, updateJson, } from '@nrwl/devkit'; -import { getImportPath } from 'nx/src/utils/path'; import { getRootTsConfigPathInTree } from '../../../utilities/typescript'; import { Schema } from '../schema'; +import { + createProjectRootMappings, + findProjectForPath, +} from 'nx/src/project-graph/utils/find-project-for-path'; /** * Updates the tsconfig paths to remove the project. * * @param schema The options provided to the schematic */ -export function updateTsconfig( - tree: Tree, - schema: Schema, - project: ProjectConfiguration -) { - const { appsDir, libsDir, npmScope } = getWorkspaceLayout(tree); - +export async function updateTsconfig(tree: Tree, schema: Schema) { const tsConfigPath = getRootTsConfigPathInTree(tree); - const defaultImportPath = getImportPath( - npmScope, - project.root - .slice( - project.projectType === 'application' ? appsDir.length : libsDir.length - ) - .replace(/^\/|\\/, '') - ); - const importPath = schema.importPath || defaultImportPath; + if (tree.exists(tsConfigPath)) { + const graph: ProjectGraph = await createProjectGraphAsync(); + const projectMapping = createProjectRootMappings(graph.nodes); updateJson(tree, tsConfigPath, (json) => { - delete json.compilerOptions.paths[importPath]; + for (const importPath in json.compilerOptions.paths) { + for (const path of json.compilerOptions.paths[importPath]) { + const project = findProjectForPath( + normalizePath(path), + projectMapping + ); + if (project === schema.projectName) { + delete json.compilerOptions.paths[importPath]; + break; + } + } + } return json; }); } diff --git a/packages/workspace/src/generators/remove/remove.ts b/packages/workspace/src/generators/remove/remove.ts index 54b24bbc112ee..6d77c8d128f7b 100644 --- a/packages/workspace/src/generators/remove/remove.ts +++ b/packages/workspace/src/generators/remove/remove.ts @@ -1,6 +1,8 @@ import { convertNxGenerator, + createProjectGraphAsync, formatFiles, + ProjectGraph, readProjectConfiguration, Tree, } from '@nrwl/devkit'; @@ -20,7 +22,7 @@ export async function removeGenerator(tree: Tree, schema: Schema) { updateJestConfig(tree, schema, project); removeProjectConfig(tree, schema); removeProject(tree, project); - updateTsconfig(tree, schema, project); + await updateTsconfig(tree, schema); if (!schema.skipFormat) { await formatFiles(tree); }