fix(misc): fix misc issues with move generators (#17814)

This commit is contained in:
Leosvel Pérez Espinosa 2023-06-28 15:26:45 +01:00 committed by GitHub
parent c0508e38e3
commit 7055c724dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 362 additions and 109 deletions

View File

@ -0,0 +1,4 @@
export * from './normalize-schema';
export * from './update-module-name';
export * from './update-ng-package';
export * from './update-secondary-entry-points';

View File

@ -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,
};
}

View File

@ -4,7 +4,7 @@ import { Linter } from '@nx/linter';
import { moveGenerator } from '@nx/workspace/generators'; import { moveGenerator } from '@nx/workspace/generators';
import { UnitTestRunner } from '../../../utils/test-runners'; import { UnitTestRunner } from '../../../utils/test-runners';
import { generateTestLibrary } from '../../utils/testing'; import { generateTestLibrary } from '../../utils/testing';
import { Schema } from '../schema'; import { NormalizedSchema } from '../schema';
import { updateModuleName } from './update-module-name'; import { updateModuleName } from './update-module-name';
describe('updateModuleName Rule', () => { describe('updateModuleName Rule', () => {
@ -20,17 +20,19 @@ describe('updateModuleName Rule', () => {
name: 'my-first', name: 'my-first',
simpleName: true, simpleName: true,
}); });
const schema: Schema = { const schema: NormalizedSchema = {
projectName: 'my-first', projectName: 'my-first',
destination: 'my/first', destination: 'my/first',
updateImportPath: true, updateImportPath: true,
newProjectName: 'my-first',
oldProjectRoot: 'libs/my-first',
}; };
await moveGenerator(tree, schema); await moveGenerator(tree, schema);
updateModuleName(tree, { ...schema, destination: 'my/first' }); updateModuleName(tree, { ...schema, destination: 'my/first' });
expect(tree.exists(updatedModulePath)).toBe(true); 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 {}`); expect(moduleFile).toContain(`export class MyFirstModule {}`);
}); });
@ -42,10 +44,12 @@ describe('updateModuleName Rule', () => {
const indexPath = '/libs/shared/my-first/src/index.ts'; const indexPath = '/libs/shared/my-first/src/index.ts';
const secondModulePath = '/libs/my-second/src/lib/my-second.module.ts'; const secondModulePath = '/libs/my-second/src/lib/my-second.module.ts';
const schema: Schema = { const schema: NormalizedSchema = {
projectName: 'my-first', projectName: 'my-first',
destination: 'shared/my-first', destination: 'shared/my-first',
updateImportPath: true, updateImportPath: true,
newProjectName: 'shared-my-first',
oldProjectRoot: 'libs/my-first',
}; };
beforeEach(async () => { beforeEach(async () => {
@ -111,10 +115,10 @@ describe('updateModuleName Rule', () => {
expect(tree.exists(updatedModulePath)).toBe(true); expect(tree.exists(updatedModulePath)).toBe(true);
expect(tree.exists(updatedModuleSpecPath)).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 {}`); expect(moduleFile).toContain(`export class SharedMyFirstModule {}`);
const moduleSpecFile = tree.read(updatedModuleSpecPath).toString('utf-8'); const moduleSpecFile = tree.read(updatedModuleSpecPath, 'utf-8');
expect(moduleSpecFile).toContain( expect(moduleSpecFile).toContain(
`import { SharedMyFirstModule } from './shared-my-first.module';` `import { SharedMyFirstModule } from './shared-my-first.module';`
); );
@ -130,7 +134,7 @@ describe('updateModuleName Rule', () => {
it('should update any references to the module', async () => { it('should update any references to the module', async () => {
updateModuleName(tree, schema); updateModuleName(tree, schema);
const importerFile = tree.read(secondModulePath).toString('utf-8'); const importerFile = tree.read(secondModulePath, 'utf-8');
expect(importerFile).toContain( expect(importerFile).toContain(
`import { SharedMyFirstModule } from '@proj/shared/my-first';` `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 () => { it('should update the index.ts file which exports the module', async () => {
updateModuleName(tree, schema); updateModuleName(tree, schema);
const indexFile = tree.read(indexPath).toString('utf-8'); const indexFile = tree.read(indexPath, 'utf-8');
expect(indexFile).toContain( expect(indexFile).toContain(
`export * from './lib/shared-my-first.module';` `export * from './lib/shared-my-first.module';`
); );
@ -150,10 +154,12 @@ describe('updateModuleName Rule', () => {
}); });
describe('rename', () => { describe('rename', () => {
const schema: Schema = { const schema: NormalizedSchema = {
projectName: 'my-source', projectName: 'my-source',
destination: 'my-destination', destination: 'my-destination',
updateImportPath: true, updateImportPath: true,
newProjectName: 'my-destination',
oldProjectRoot: 'libs/my-source',
}; };
const modulePath = '/libs/my-destination/src/lib/my-destination.module.ts'; 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(modulePath)).toBe(true);
expect(tree.exists(moduleSpecPath)).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 {}`); expect(moduleFile).toContain(`export class MyDestinationModule {}`);
const moduleSpecFile = tree.read(moduleSpecPath).toString('utf-8'); const moduleSpecFile = tree.read(moduleSpecPath, 'utf-8');
expect(moduleSpecFile).toContain( expect(moduleSpecFile).toContain(
`import { MyDestinationModule } from './my-destination.module';` `import { MyDestinationModule } from './my-destination.module';`
); );
@ -252,7 +258,7 @@ describe('updateModuleName Rule', () => {
it('should update any references to the module', async () => { it('should update any references to the module', async () => {
updateModuleName(tree, schema); updateModuleName(tree, schema);
const importerFile = tree.read(importerPath).toString('utf-8'); const importerFile = tree.read(importerPath, 'utf-8');
expect(importerFile).toContain( expect(importerFile).toContain(
`import { MyDestinationModule } from '@proj/my-destination';` `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 () => { it('should update the index.ts file which exports the module', async () => {
updateModuleName(tree, schema); updateModuleName(tree, schema);
const indexFile = tree.read(indexPath).toString('utf-8'); const indexFile = tree.read(indexPath, 'utf-8');
expect(indexFile).toContain( expect(indexFile).toContain(
`export * from './lib/my-destination.module';` `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 {}`);
});
}); });
}); });

View File

@ -1,13 +1,12 @@
import { import {
getProjects, getProjects,
joinPathFragments,
names, names,
readProjectConfiguration, readProjectConfiguration,
Tree, Tree,
visitNotIgnoredFiles, visitNotIgnoredFiles,
} from '@nx/devkit'; } from '@nx/devkit';
import { getNewProjectName } from '../../utils/get-new-project-name'; import type { NormalizedSchema } from '../schema';
import { join } from 'path';
import { Schema } from '../schema';
/** /**
* Updates the Angular module name (including the spec file and index.ts) * Updates the Angular module name (including the spec file and index.ts)
@ -19,10 +18,8 @@ import { Schema } from '../schema';
*/ */
export function updateModuleName( export function updateModuleName(
tree: Tree, tree: Tree,
{ projectName, destination }: Schema { projectName: oldProjectName, newProjectName }: NormalizedSchema
): void { ): void {
const newProjectName = getNewProjectName(destination);
const project = readProjectConfiguration(tree, newProjectName); const project = readProjectConfiguration(tree, newProjectName);
if (project.projectType === 'application') { if (project.projectType === 'application') {
@ -32,14 +29,14 @@ export function updateModuleName(
} }
const moduleName = { const moduleName = {
from: names(projectName).className, from: `${names(oldProjectName).className}Module`,
to: names(newProjectName).className, to: `${names(newProjectName).className}Module`,
}; };
const findModuleName = new RegExp(`\\b${moduleName.from}`, 'g'); const findModuleName = new RegExp(`\\b${moduleName.from}`, 'g');
const moduleFile = { const moduleFile = {
from: `${projectName}.module`, from: `${oldProjectName}.module`,
to: `${newProjectName}.module`, to: `${newProjectName}.module`,
}; };
@ -81,7 +78,7 @@ export function updateModuleName(
}); });
// update index file // update index file
const indexFile = join(project.sourceRoot, 'index.ts'); const indexFile = joinPathFragments(project.sourceRoot, 'index.ts');
if (tree.exists(indexFile)) { if (tree.exists(indexFile)) {
updateFileContent(tree, replacements, indexFile); updateFileContent(tree, replacements, indexFile);
} }

View File

@ -6,13 +6,11 @@ import {
updateJson, updateJson,
workspaceRoot, workspaceRoot,
} from '@nx/devkit'; } from '@nx/devkit';
import { getNewProjectName } from '../../utils/get-new-project-name';
import { join, relative } from 'path'; import { join, relative } from 'path';
import { Schema } from '../schema'; import type { NormalizedSchema } from '../schema';
export function updateNgPackage(tree: Tree, schema: Schema): void { export function updateNgPackage(tree: Tree, schema: NormalizedSchema): void {
const newProjectName = getNewProjectName(schema.destination); const project = readProjectConfiguration(tree, schema.newProjectName);
const project = readProjectConfiguration(tree, newProjectName);
if (project.projectType === 'application') { if (project.projectType === 'application') {
return; return;
@ -29,13 +27,13 @@ export function updateNgPackage(tree: Tree, schema: Schema): void {
const outputs = getOutputsForTargetAndConfiguration( const outputs = getOutputsForTargetAndConfiguration(
{ {
target: { target: {
project: newProjectName, project: schema.newProjectName,
target: 'build', target: 'build',
}, },
overrides: {}, overrides: {},
}, },
{ {
name: newProjectName, name: schema.newProjectName,
type: 'lib', type: 'lib',
data: { data: {
root: project.root, root: project.root,

View File

@ -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);
}

View File

@ -3,6 +3,7 @@ import { readJson, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/linter'; import { Linter } from '@nx/linter';
import { UnitTestRunner } from '../../utils/test-runners'; import { UnitTestRunner } from '../../utils/test-runners';
import librarySecondaryEntryPointGenerator from '../library-secondary-entry-point/library-secondary-entry-point';
import { generateTestLibrary } from '../utils/testing'; import { generateTestLibrary } from '../utils/testing';
import { angularMoveGenerator } from './move'; import { angularMoveGenerator } from './move';
@ -50,6 +51,28 @@ describe('@nx/angular:move', () => {
expect(ngPackageJson.dest).toEqual('../../dist/libs/mynewlib2'); 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 () => { it('should format files', async () => {
jest.spyOn(devkit, 'formatFiles'); jest.spyOn(devkit, 'formatFiles');

View File

@ -1,8 +1,12 @@
import { formatFiles, Tree } from '@nx/devkit'; import { formatFiles, Tree } from '@nx/devkit';
import { moveGenerator } from '@nx/workspace/generators'; import { moveGenerator } from '@nx/workspace/generators';
import { updateModuleName } from './lib/update-module-name'; import {
import { updateNgPackage } from './lib/update-ng-package'; normalizeSchema,
import { Schema } from './schema'; updateModuleName,
updateNgPackage,
updateSecondaryEntryPoints,
} from './lib';
import type { Schema } from './schema';
/** /**
* Moves an Angular lib/app to another folder (and renames it in the process) * Moves an Angular lib/app to another folder (and renames it in the process)
@ -15,11 +19,14 @@ export async function angularMoveGenerator(
tree: Tree, tree: Tree,
schema: Schema schema: Schema
): Promise<void> { ): Promise<void> {
await moveGenerator(tree, { ...schema, skipFormat: true }); const normalizedSchema = normalizeSchema(tree, schema);
updateModuleName(tree, schema);
updateNgPackage(tree, schema);
if (!schema.skipFormat) { await moveGenerator(tree, { ...schema, skipFormat: true });
updateModuleName(tree, normalizedSchema);
updateNgPackage(tree, normalizedSchema);
updateSecondaryEntryPoints(tree, normalizedSchema);
if (!normalizedSchema.skipFormat) {
await formatFiles(tree); await formatFiles(tree);
} }
} }

View File

@ -5,3 +5,8 @@ export interface Schema {
importPath?: string; importPath?: string;
skipFormat?: boolean; skipFormat?: boolean;
} }
export interface NormalizedSchema extends Schema {
oldProjectRoot: string;
newProjectName: string;
}

View File

@ -1,8 +1,15 @@
import { normalizePath } from '@nx/devkit';
/** /**
* Replaces slashes with dashes * Joins path segments replacing slashes with dashes
* *
* @param path * @param path
*/ */
export function getNewProjectName(path: string): string { 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('-');
} }

View File

@ -46,6 +46,25 @@ describe('normalizeSchema', () => {
expect(result).toEqual(expected); 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', () => { it('should use provided import path', () => {
const expected: NormalizedSchema = { const expected: NormalizedSchema = {
destination: 'my/library', destination: 'my/library',

View File

@ -1,6 +1,10 @@
import { ProjectConfiguration, Tree } from '@nx/devkit'; import { ProjectConfiguration, Tree } from '@nx/devkit';
import type { NormalizedSchema, Schema } from '../schema'; 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'; import { getImportPath } from '../../../utilities/get-import-path';
export function normalizeSchema( export function normalizeSchema(
@ -8,9 +12,7 @@ export function normalizeSchema(
schema: Schema, schema: Schema,
projectConfiguration: ProjectConfiguration projectConfiguration: ProjectConfiguration
): NormalizedSchema { ): NormalizedSchema {
const destination = schema.destination.startsWith('/') const destination = normalizePathSlashes(schema.destination);
? normalizeSlashes(schema.destination.slice(1))
: schema.destination;
const newProjectName = const newProjectName =
schema.newProjectName ?? getNewProjectName(destination); schema.newProjectName ?? getNewProjectName(destination);
@ -18,7 +20,8 @@ export function normalizeSchema(
...schema, ...schema,
destination, destination,
importPath: importPath:
schema.importPath ?? normalizeSlashes(getImportPath(tree, destination)), schema.importPath ??
normalizePathSlashes(getImportPath(tree, destination)),
newProjectName, newProjectName,
relativeToRootDestination: getDestination( relativeToRootDestination: getDestination(
tree, tree,

View File

@ -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 { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Schema } from '../schema'; import { Schema } from '../schema';
import { updateImports } from './update-imports'; 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 () => { it('should update project ref of a project not under libs in the root tsconfig.base.json', async () => {
tree.delete('libs'); tree.delete('libs');
await libraryGenerator(tree, { await libraryGenerator(tree, {

View File

@ -17,7 +17,7 @@ import {
findNodes, findNodes,
} from '../../../utilities/ts-config'; } from '../../../utilities/ts-config';
import { NormalizedSchema } from '../schema'; import { NormalizedSchema } from '../schema';
import { normalizeSlashes } from './utils'; import { normalizePathSlashes } from './utils';
import { relative } from 'path'; import { relative } from 'path';
import { ensureTypescript } from '../../../utilities/typescript'; import { ensureTypescript } from '../../../utilities/typescript';
import { getImportPath } from '../../../utilities/get-import-path'; import { getImportPath } from '../../../utilities/get-import-path';
@ -39,37 +39,63 @@ export function updateImports(
return; return;
} }
const { npmScope, libsDir } = getWorkspaceLayout(tree); const { libsDir } = getWorkspaceLayout(tree);
const projects = getProjects(tree); const projects = getProjects(tree);
// use the source root to find the from location // use the source root to find the from location
// this attempts to account for libs that have been created with --importPath // this attempts to account for libs that have been created with --importPath
const tsConfigPath = getRootTsConfigPathInTree(tree); const tsConfigPath = getRootTsConfigPathInTree(tree);
let tsConfig: any; let tsConfig: any;
let fromPath: string; let mainEntryPointImportPath: string;
let secondaryEntryPointImportPaths: string[];
if (tree.exists(tsConfigPath)) { if (tree.exists(tsConfigPath)) {
tsConfig = readJson(tree, 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) => 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 = { mainEntryPointImportPath ??= normalizePathSlashes(
from:
fromPath ||
normalizeSlashes(
getImportPath( getImportPath(
tree, tree,
project.root.slice(libsDir.length).replace(/^\/|\\/, '') project.root.slice(libsDir.length).replace(/^\/|\\/, '')
) )
), );
to: schema.importPath,
};
if (schema.updateImportPath) { 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'); const replaceProjectRef = new RegExp(projectRef.from, 'g');
for (const [name, definition] of Array.from(projects.entries())) { for (const [name, definition] of Array.from(projects.entries())) {
@ -108,7 +134,7 @@ export function updateImports(
joinPathFragments(projectRoot.to, relative(projectRoot.from, x)) joinPathFragments(projectRoot.to, relative(projectRoot.from, x))
); );
if (schema.updateImportPath) { if (schema.updateImportPath && projectRef.to) {
tsConfig.compilerOptions.paths[projectRef.to] = updatedPath; tsConfig.compilerOptions.paths[projectRef.to] = updatedPath;
if (projectRef.from !== projectRef.to) { if (projectRef.from !== projectRef.to) {
delete tsConfig.compilerOptions.paths[projectRef.from]; delete tsConfig.compilerOptions.paths[projectRef.from];
@ -116,11 +142,16 @@ export function updateImports(
} else { } else {
tsConfig.compilerOptions.paths[projectRef.from] = updatedPath; tsConfig.compilerOptions.paths[projectRef.from] = updatedPath;
} }
}
writeJson(tree, tsConfigPath, tsConfig); writeJson(tree, tsConfigPath, tsConfig);
} }
} }
function ensureTrailingSlash(path: string): string {
return path.endsWith('/') ? path : `${path}/`;
}
/** /**
* Changes imports in a file from one import to another * Changes imports in a file from one import to another
*/ */

View File

@ -1,10 +1,10 @@
import { import {
getWorkspaceLayout, getWorkspaceLayout,
joinPathFragments, joinPathFragments,
normalizePath,
ProjectConfiguration, ProjectConfiguration,
Tree, Tree,
} from '@nx/devkit'; } from '@nx/devkit';
import { Schema } from '../schema'; import { Schema } from '../schema';
/** /**
@ -35,12 +35,17 @@ export function getDestination(
} }
/** /**
* Replaces slashes with dashes * Joins path segments replacing slashes with dashes
* *
* @param path * @param path
*/ */
export function getNewProjectName(path: string): string { 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 * @param input
*/ */
export function normalizeSlashes(input: string): string { export function normalizePathSlashes(input: string): string {
return input return (
normalizePath(input)
// strip leading ./ or /
.replace(/^\.?\//, '')
.split('/') .split('/')
.filter((x) => !!x) .filter((x) => !!x)
.join('/'); .join('/')
);
} }