feat(misc): support new format to determine new project name and destination in move generators (#18878)
Co-authored-by: Jason Jean <jasonjean1993@gmail.com>
This commit is contained in:
parent
6b272ed4c4
commit
8564d9ba12
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "move",
|
"name": "move",
|
||||||
"factory": "./src/generators/move/move#angularMoveGenerator",
|
"factory": "./src/generators/move/move#angularMoveGeneratorInternal",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"$id": "NxAngularMove",
|
"$id": "NxAngularMove",
|
||||||
@ -22,12 +22,24 @@
|
|||||||
"x-dropdown": "projects",
|
"x-dropdown": "projects",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"newProjectName": {
|
||||||
|
"type": "string",
|
||||||
|
"alias": "project",
|
||||||
|
"description": "The new name of the project after the move.",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"destination": {
|
"destination": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The folder to move the Angular project into.",
|
"description": "The folder to move the Angular project into.",
|
||||||
"$default": { "$source": "argv", "index": 0 },
|
"$default": { "$source": "argv", "index": 0 },
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"projectNameAndRootFormat": {
|
||||||
|
"description": "Whether to generate the new project name and destination as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["as-provided", "derived"]
|
||||||
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The new import path to use in the `tsconfig.base.json`."
|
"description": "The new import path to use in the `tsconfig.base.json`."
|
||||||
@ -50,7 +62,8 @@
|
|||||||
},
|
},
|
||||||
"aliases": ["mv"],
|
"aliases": ["mv"],
|
||||||
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration.",
|
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration.",
|
||||||
"implementation": "/packages/angular/src/generators/move/move#angularMoveGenerator.ts",
|
"x-deprecated": "Use the `@nx/workspace:move` generator instead. This generator will be removed in Nx v18.",
|
||||||
|
"implementation": "/packages/angular/src/generators/move/move#angularMoveGeneratorInternal.ts",
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"path": "/packages/angular/src/generators/move/schema.json",
|
"path": "/packages/angular/src/generators/move/schema.json",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "move",
|
"name": "move",
|
||||||
"factory": "./src/generators/move/move#moveGenerator",
|
"factory": "./src/generators/move/move#moveGeneratorInternal",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"$id": "NxWorkspaceMove",
|
"$id": "NxWorkspaceMove",
|
||||||
@ -21,11 +21,23 @@
|
|||||||
"description": "The name of the project to move.",
|
"description": "The name of the project to move.",
|
||||||
"x-dropdown": "projects"
|
"x-dropdown": "projects"
|
||||||
},
|
},
|
||||||
|
"newProjectName": {
|
||||||
|
"type": "string",
|
||||||
|
"alias": "project",
|
||||||
|
"description": "The new name of the project after the move.",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"destination": {
|
"destination": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The folder to move the project into.",
|
"description": "The folder to move the project into.",
|
||||||
"$default": { "$source": "argv", "index": 0 }
|
"$default": { "$source": "argv", "index": 0 }
|
||||||
},
|
},
|
||||||
|
"projectNameAndRootFormat": {
|
||||||
|
"description": "Whether to generate the new project name and destination as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["as-provided", "derived"]
|
||||||
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The new import path to use in the `tsconfig.base.json`."
|
"description": "The new import path to use in the `tsconfig.base.json`."
|
||||||
@ -48,7 +60,7 @@
|
|||||||
},
|
},
|
||||||
"aliases": ["mv"],
|
"aliases": ["mv"],
|
||||||
"description": "Move an application or library to another folder.",
|
"description": "Move an application or library to another folder.",
|
||||||
"implementation": "/packages/workspace/src/generators/move/move#moveGenerator.ts",
|
"implementation": "/packages/workspace/src/generators/move/move#moveGeneratorInternal.ts",
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"path": "/packages/workspace/src/generators/move/schema.json",
|
"path": "/packages/workspace/src/generators/move/schema.json",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
|
|||||||
@ -20,7 +20,9 @@ describe('Move Angular Project', () => {
|
|||||||
app1 = uniq('app1');
|
app1 = uniq('app1');
|
||||||
app2 = uniq('app2');
|
app2 = uniq('app2');
|
||||||
newPath = `subfolder/${app2}`;
|
newPath = `subfolder/${app2}`;
|
||||||
runCLI(`generate @nx/angular:app ${app1} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/angular:app ${app1} --project-name-and-root-format=as-provided --no-interactive`
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => cleanupProject());
|
afterAll(() => cleanupProject());
|
||||||
@ -30,28 +32,26 @@ describe('Move Angular Project', () => {
|
|||||||
*/
|
*/
|
||||||
it('should work for apps', () => {
|
it('should work for apps', () => {
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/angular:move --project ${app1} ${newPath}`
|
`generate @nx/angular:move --project ${app1} ${newPath} --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
// just check the output
|
// just check the output
|
||||||
expect(moveOutput).toContain(`DELETE apps/${app1}`);
|
expect(moveOutput).toContain(`DELETE ${app1}`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/jest.config.ts`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/jest.config.ts`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.app.json`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.app.json`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.json`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.json`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/tsconfig.spec.json`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.spec.json`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/.eslintrc.json`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/.eslintrc.json`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/favicon.ico`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/favicon.ico`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/index.html`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/index.html`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/main.ts`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/main.ts`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/styles.css`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/styles.css`);
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/test-setup.ts`);
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/test-setup.ts`);
|
||||||
expect(moveOutput).toContain(
|
expect(moveOutput).toContain(
|
||||||
`CREATE apps/${newPath}/src/app/app.component.html`
|
`CREATE ${newPath}/src/app/app.component.html`
|
||||||
);
|
);
|
||||||
expect(moveOutput).toContain(
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/app/app.module.ts`);
|
||||||
`CREATE apps/${newPath}/src/app/app.module.ts`
|
expect(moveOutput).toContain(`CREATE ${newPath}/src/assets/.gitkeep`);
|
||||||
);
|
|
||||||
expect(moveOutput).toContain(`CREATE apps/${newPath}/src/assets/.gitkeep`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -61,7 +61,7 @@ describe('Move Angular Project', () => {
|
|||||||
// by default the cypress config doesn't contain any app specific paths
|
// by default the cypress config doesn't contain any app specific paths
|
||||||
// create a custom config with some app specific paths
|
// create a custom config with some app specific paths
|
||||||
updateFile(
|
updateFile(
|
||||||
`apps/${app1}-e2e/cypress.config.ts`,
|
`${app1}-e2e/cypress.config.ts`,
|
||||||
`
|
`
|
||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
||||||
@ -69,27 +69,25 @@ describe('Move Angular Project', () => {
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
...nxE2EPreset(__dirname),
|
...nxE2EPreset(__dirname),
|
||||||
videosFolder: '../../dist/cypress/apps/${app1}-e2e/videos',
|
videosFolder: '../dist/cypress/${app1}-e2e/videos',
|
||||||
screenshotsFolder: '../../dist/cypress/apps/${app1}-e2e/screenshots',
|
screenshotsFolder: '../dist/cypress/${app1}-e2e/screenshots',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/angular:move --projectName=${app1}-e2e --destination=${newPath}-e2e`
|
`generate @nx/angular:move --projectName=${app1}-e2e --destination=${newPath}-e2e --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
// just check that the cypress.config.ts is updated correctly
|
// just check that the cypress.config.ts is updated correctly
|
||||||
const cypressConfigPath = `apps/${newPath}-e2e/cypress.config.ts`;
|
const cypressConfigPath = `${newPath}-e2e/cypress.config.ts`;
|
||||||
expect(moveOutput).toContain(`CREATE ${cypressConfigPath}`);
|
expect(moveOutput).toContain(`CREATE ${cypressConfigPath}`);
|
||||||
checkFilesExist(cypressConfigPath);
|
checkFilesExist(cypressConfigPath);
|
||||||
const cypressConfig = readFile(cypressConfigPath);
|
const cypressConfig = readFile(cypressConfigPath);
|
||||||
|
|
||||||
|
expect(cypressConfig).toContain(`../../dist/cypress/${newPath}-e2e/videos`);
|
||||||
expect(cypressConfig).toContain(
|
expect(cypressConfig).toContain(
|
||||||
`../../../dist/cypress/apps/${newPath}-e2e/videos`
|
`../../dist/cypress/${newPath}-e2e/screenshots`
|
||||||
);
|
|
||||||
expect(cypressConfig).toContain(
|
|
||||||
`../../../dist/cypress/apps/${newPath}-e2e/screenshots`
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -99,13 +97,73 @@ describe('Move Angular Project', () => {
|
|||||||
it('should work for libraries', () => {
|
it('should work for libraries', () => {
|
||||||
const lib1 = uniq('mylib');
|
const lib1 = uniq('mylib');
|
||||||
const lib2 = uniq('mylib');
|
const lib2 = uniq('mylib');
|
||||||
runCLI(`generate @nx/angular:lib ${lib1} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/angular:lib ${lib1} --project-name-and-root-format=as-provided --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a library which imports the module from the other lib
|
* Create a library which imports the module from the other lib
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/angular:lib ${lib2} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/angular:lib ${lib2} --project-name-and-root-format=as-provided --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`${lib2}/src/lib/${lib2}.module.ts`,
|
||||||
|
`import { ${classify(lib1)}Module } from '@${proj}/${lib1}';
|
||||||
|
|
||||||
|
export class ExtendedModule extends ${classify(lib1)}Module { }`
|
||||||
|
);
|
||||||
|
|
||||||
|
const moveOutput = runCLI(
|
||||||
|
`generate @nx/angular:move --projectName=${lib1} --destination=shared/${lib1} --newProjectName=shared-${lib1} --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
|
const newPath = `shared/${lib1}`;
|
||||||
|
const newModule = `Shared${classify(lib1)}Module`;
|
||||||
|
|
||||||
|
const testSetupPath = `${newPath}/src/test-setup.ts`;
|
||||||
|
expect(moveOutput).toContain(`CREATE ${testSetupPath}`);
|
||||||
|
checkFilesExist(testSetupPath);
|
||||||
|
|
||||||
|
const modulePath = `${newPath}/src/lib/shared-${lib1}.module.ts`;
|
||||||
|
expect(moveOutput).toContain(`CREATE ${modulePath}`);
|
||||||
|
checkFilesExist(modulePath);
|
||||||
|
const moduleFile = readFile(modulePath);
|
||||||
|
expect(moduleFile).toContain(`export class ${newModule}`);
|
||||||
|
|
||||||
|
const indexPath = `${newPath}/src/index.ts`;
|
||||||
|
expect(moveOutput).toContain(`CREATE ${indexPath}`);
|
||||||
|
checkFilesExist(indexPath);
|
||||||
|
const index = readFile(indexPath);
|
||||||
|
expect(index).toContain(`export * from './lib/shared-${lib1}.module'`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the import in lib2 has been updated
|
||||||
|
*/
|
||||||
|
const lib2FilePath = `${lib2}/src/lib/${lib2}.module.ts`;
|
||||||
|
const lib2File = readFile(lib2FilePath);
|
||||||
|
expect(lib2File).toContain(
|
||||||
|
`import { ${newModule} } from '@${proj}/shared-${lib1}';`
|
||||||
|
);
|
||||||
|
expect(lib2File).toContain(`extends ${newModule}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move projects correctly with --project-name-and-root-format=derived', () => {
|
||||||
|
const lib1 = uniq('mylib');
|
||||||
|
const lib2 = uniq('mylib');
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/angular:lib ${lib1} --project-name-and-root-format=derived --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a library which imports the module from the other lib
|
||||||
|
*/
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/angular:lib ${lib2} --project-name-and-root-format=derived --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib2}/src/lib/${lib2}.module.ts`,
|
`libs/${lib2}/src/lib/${lib2}.module.ts`,
|
||||||
@ -115,7 +173,7 @@ describe('Move Angular Project', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/angular:move --projectName=${lib1} --destination=shared/${lib1}`
|
`generate @nx/angular:move --projectName=${lib1} --destination=shared/${lib1} --project-name-and-root-format=derived`
|
||||||
);
|
);
|
||||||
|
|
||||||
const newPath = `libs/shared/${lib1}`;
|
const newPath = `libs/shared/${lib1}`;
|
||||||
|
|||||||
@ -83,15 +83,17 @@ describe('Workspace Tests', () => {
|
|||||||
const lib1 = uniq('mylib');
|
const lib1 = uniq('mylib');
|
||||||
const lib2 = uniq('mylib');
|
const lib2 = uniq('mylib');
|
||||||
const lib3 = uniq('mylib');
|
const lib3 = uniq('mylib');
|
||||||
runCLI(`generate @nx/js:lib ${lib1}/data-access --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib1}-data-access --directory=${lib1}/data-access --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
`${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
||||||
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/index.ts`,
|
`${lib1}/data-access/src/index.ts`,
|
||||||
`export * from './lib/${lib1}-data-access.ts'`
|
`export * from './lib/${lib1}-data-access.ts'`
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -99,11 +101,13 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which imports a class from lib1
|
* Create a library which imports a class from lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib2}-ui --directory=${lib2}/ui --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
`${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
||||||
`import { fromLibOne } from '@${proj}/${lib1}/data-access';
|
`import { fromLibOne } from '@${proj}/${lib1}-data-access';
|
||||||
|
|
||||||
export const fromLibTwo = () => fromLibOne();`
|
export const fromLibTwo = () => fromLibOne();`
|
||||||
);
|
);
|
||||||
@ -112,7 +116,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which has an implicit dependency on lib1
|
* Create a library which has an implicit dependency on lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib3} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
await updateProjectConfig(lib3, (config) => {
|
await updateProjectConfig(lib3, (config) => {
|
||||||
config.implicitDependencies = [`${lib1}-data-access`];
|
config.implicitDependencies = [`${lib1}-data-access`];
|
||||||
return config;
|
return config;
|
||||||
@ -123,13 +129,13 @@ describe('Workspace Tests', () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
|
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access --newProjectName=shared-${lib1}-data-access --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(moveOutput).toContain(`DELETE libs/${lib1}/data-access`);
|
expect(moveOutput).toContain(`DELETE ${lib1}/data-access`);
|
||||||
expect(exists(`libs/${lib1}/data-access`)).toBeFalsy();
|
expect(exists(`${lib1}/data-access`)).toBeFalsy();
|
||||||
|
|
||||||
const newPath = `libs/shared/${lib1}/data-access`;
|
const newPath = `shared/${lib1}/data-access`;
|
||||||
const newName = `shared-${lib1}-data-access`;
|
const newName = `shared-${lib1}-data-access`;
|
||||||
|
|
||||||
const readmePath = `${newPath}/README.md`;
|
const readmePath = `${newPath}/README.md`;
|
||||||
@ -141,8 +147,8 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(jestConfigPath);
|
checkFilesExist(jestConfigPath);
|
||||||
const jestConfig = readFile(jestConfigPath);
|
const jestConfig = readFile(jestConfigPath);
|
||||||
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
|
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
|
||||||
expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`);
|
expect(jestConfig).toContain(`preset: '../../../jest.preset.js'`);
|
||||||
expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`);
|
expect(jestConfig).toContain(`'../../../coverage/${newPath}'`);
|
||||||
|
|
||||||
const tsConfigPath = `${newPath}/tsconfig.json`;
|
const tsConfigPath = `${newPath}/tsconfig.json`;
|
||||||
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
||||||
@ -153,7 +159,7 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(tsConfigLibPath);
|
checkFilesExist(tsConfigLibPath);
|
||||||
const tsConfigLib = readJson(tsConfigLibPath);
|
const tsConfigLib = readJson(tsConfigLibPath);
|
||||||
expect(tsConfigLib.compilerOptions.outDir).toEqual(
|
expect(tsConfigLib.compilerOptions.outDir).toEqual(
|
||||||
'../../../../dist/out-tsc'
|
'../../../dist/out-tsc'
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
||||||
@ -161,7 +167,7 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(tsConfigSpecPath);
|
checkFilesExist(tsConfigSpecPath);
|
||||||
const tsConfigSpec = readJson(tsConfigSpecPath);
|
const tsConfigSpec = readJson(tsConfigSpecPath);
|
||||||
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
|
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
|
||||||
'../../../../dist/out-tsc'
|
'../../../dist/out-tsc'
|
||||||
);
|
);
|
||||||
|
|
||||||
const indexPath = `${newPath}/src/index.ts`;
|
const indexPath = `${newPath}/src/index.ts`;
|
||||||
@ -186,13 +192,13 @@ describe('Workspace Tests', () => {
|
|||||||
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
||||||
const rootTsConfig = readJson('tsconfig.base.json');
|
const rootTsConfig = readJson('tsconfig.base.json');
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}-data-access`]
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[
|
rootTsConfig.compilerOptions.paths[
|
||||||
`@${proj}/shared/${lib1}/data-access`
|
`@${proj}/shared-${lib1}-data-access`
|
||||||
]
|
]
|
||||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
).toEqual([`shared/${lib1}/data-access/src/index.ts`]);
|
||||||
|
|
||||||
projects = await readResolvedConfiguration();
|
projects = await readResolvedConfiguration();
|
||||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||||
@ -200,17 +206,17 @@ describe('Workspace Tests', () => {
|
|||||||
expect(project).toBeTruthy();
|
expect(project).toBeTruthy();
|
||||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||||
`libs/shared/${lib1}/data-access/**/*.ts`,
|
`shared/${lib1}/data-access/**/*.ts`,
|
||||||
`libs/shared/${lib1}/data-access/package.json`,
|
`shared/${lib1}/data-access/package.json`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the import in lib2 has been updated
|
* Check that the import in lib2 has been updated
|
||||||
*/
|
*/
|
||||||
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
const lib2FilePath = `${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
||||||
const lib2File = readFile(lib2FilePath);
|
const lib2File = readFile(lib2FilePath);
|
||||||
expect(lib2File).toContain(
|
expect(lib2File).toContain(
|
||||||
`import { fromLibOne } from '@${proj}/shared/${lib1}/data-access';`
|
`import { fromLibOne } from '@${proj}/shared-${lib1}-data-access';`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -220,16 +226,16 @@ describe('Workspace Tests', () => {
|
|||||||
const lib2 = uniq('mylib');
|
const lib2 = uniq('mylib');
|
||||||
const lib3 = uniq('mylib');
|
const lib3 = uniq('mylib');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/js:lib ${lib1}/data-access --importPath=${importPath} --unitTestRunner=jest`
|
`generate @nx/js:lib ${lib1}-data-access --directory=${lib1}/data-access --importPath=${importPath} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
`${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
||||||
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/index.ts`,
|
`${lib1}/data-access/src/index.ts`,
|
||||||
`export * from './lib/${lib1}-data-access.ts'`
|
`export * from './lib/${lib1}-data-access.ts'`
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -237,10 +243,12 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which imports a class from lib1
|
* Create a library which imports a class from lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib2}-ui --directory=${lib2}/ui --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
`${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
||||||
`import { fromLibOne } from '${importPath}';
|
`import { fromLibOne } from '${importPath}';
|
||||||
|
|
||||||
export const fromLibTwo = () => fromLibOne();`
|
export const fromLibTwo = () => fromLibOne();`
|
||||||
@ -250,7 +258,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which has an implicit dependency on lib1
|
* Create a library which has an implicit dependency on lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib3} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
await updateProjectConfig(lib3, (config) => {
|
await updateProjectConfig(lib3, (config) => {
|
||||||
config.implicitDependencies = [`${lib1}-data-access`];
|
config.implicitDependencies = [`${lib1}-data-access`];
|
||||||
return config;
|
return config;
|
||||||
@ -261,13 +271,13 @@ describe('Workspace Tests', () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
|
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access --newProjectName=shared-${lib1}-data-access --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(moveOutput).toContain(`DELETE libs/${lib1}/data-access`);
|
expect(moveOutput).toContain(`DELETE ${lib1}/data-access`);
|
||||||
expect(exists(`libs/${lib1}/data-access`)).toBeFalsy();
|
expect(exists(`${lib1}/data-access`)).toBeFalsy();
|
||||||
|
|
||||||
const newPath = `libs/shared/${lib1}/data-access`;
|
const newPath = `shared/${lib1}/data-access`;
|
||||||
const newName = `shared-${lib1}-data-access`;
|
const newName = `shared-${lib1}-data-access`;
|
||||||
|
|
||||||
const readmePath = `${newPath}/README.md`;
|
const readmePath = `${newPath}/README.md`;
|
||||||
@ -279,8 +289,8 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(jestConfigPath);
|
checkFilesExist(jestConfigPath);
|
||||||
const jestConfig = readFile(jestConfigPath);
|
const jestConfig = readFile(jestConfigPath);
|
||||||
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
|
expect(jestConfig).toContain(`displayName: 'shared-${lib1}-data-access'`);
|
||||||
expect(jestConfig).toContain(`preset: '../../../../jest.preset.js'`);
|
expect(jestConfig).toContain(`preset: '../../../jest.preset.js'`);
|
||||||
expect(jestConfig).toContain(`'../../../../coverage/${newPath}'`);
|
expect(jestConfig).toContain(`'../../../coverage/${newPath}'`);
|
||||||
|
|
||||||
const tsConfigPath = `${newPath}/tsconfig.json`;
|
const tsConfigPath = `${newPath}/tsconfig.json`;
|
||||||
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
||||||
@ -291,7 +301,7 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(tsConfigLibPath);
|
checkFilesExist(tsConfigLibPath);
|
||||||
const tsConfigLib = readJson(tsConfigLibPath);
|
const tsConfigLib = readJson(tsConfigLibPath);
|
||||||
expect(tsConfigLib.compilerOptions.outDir).toEqual(
|
expect(tsConfigLib.compilerOptions.outDir).toEqual(
|
||||||
'../../../../dist/out-tsc'
|
'../../../dist/out-tsc'
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
||||||
@ -299,7 +309,7 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(tsConfigSpecPath);
|
checkFilesExist(tsConfigSpecPath);
|
||||||
const tsConfigSpec = readJson(tsConfigSpecPath);
|
const tsConfigSpec = readJson(tsConfigSpecPath);
|
||||||
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
|
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
|
||||||
'../../../../dist/out-tsc'
|
'../../../dist/out-tsc'
|
||||||
);
|
);
|
||||||
|
|
||||||
const indexPath = `${newPath}/src/index.ts`;
|
const indexPath = `${newPath}/src/index.ts`;
|
||||||
@ -313,13 +323,13 @@ describe('Workspace Tests', () => {
|
|||||||
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
||||||
const rootTsConfig = readJson('tsconfig.base.json');
|
const rootTsConfig = readJson('tsconfig.base.json');
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}-data-access`]
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[
|
rootTsConfig.compilerOptions.paths[
|
||||||
`@${proj}/shared/${lib1}/data-access`
|
`@${proj}/shared-${lib1}-data-access`
|
||||||
]
|
]
|
||||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
).toEqual([`shared/${lib1}/data-access/src/index.ts`]);
|
||||||
|
|
||||||
const projects = await readResolvedConfiguration();
|
const projects = await readResolvedConfiguration();
|
||||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||||
@ -331,21 +341,21 @@ describe('Workspace Tests', () => {
|
|||||||
expect(lib3Config.implicitDependencies).toEqual([newName]);
|
expect(lib3Config.implicitDependencies).toEqual([newName]);
|
||||||
|
|
||||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||||
`libs/shared/${lib1}/data-access/**/*.ts`,
|
`shared/${lib1}/data-access/**/*.ts`,
|
||||||
`libs/shared/${lib1}/data-access/package.json`,
|
`shared/${lib1}/data-access/package.json`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the import in lib2 has been updated
|
* Check that the import in lib2 has been updated
|
||||||
*/
|
*/
|
||||||
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
const lib2FilePath = `${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
||||||
const lib2File = readFile(lib2FilePath);
|
const lib2File = readFile(lib2FilePath);
|
||||||
expect(lib2File).toContain(
|
expect(lib2File).toContain(
|
||||||
`import { fromLibOne } from '@${proj}/shared/${lib1}/data-access';`
|
`import { fromLibOne } from '@${proj}/shared-${lib1}-data-access';`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should work for custom workspace layouts', async () => {
|
it('should work for custom workspace layouts with --project-name-and-root-format=derived', async () => {
|
||||||
const lib1 = uniq('mylib');
|
const lib1 = uniq('mylib');
|
||||||
const lib2 = uniq('mylib');
|
const lib2 = uniq('mylib');
|
||||||
const lib3 = uniq('mylib');
|
const lib3 = uniq('mylib');
|
||||||
@ -354,7 +364,9 @@ describe('Workspace Tests', () => {
|
|||||||
nxJson.workspaceLayout = { libsDir: 'packages' };
|
nxJson.workspaceLayout = { libsDir: 'packages' };
|
||||||
updateFile('nx.json', JSON.stringify(nxJson));
|
updateFile('nx.json', JSON.stringify(nxJson));
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib1}/data-access --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib1}/data-access --unitTestRunner=jest --project-name-and-root-format=derived`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`packages/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
`packages/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
||||||
@ -370,7 +382,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which imports a class from lib1
|
* Create a library which imports a class from lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest --project-name-and-root-format=derived`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`packages/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
`packages/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
||||||
@ -383,7 +397,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which has an implicit dependency on lib1
|
* Create a library which has an implicit dependency on lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib3} --unitTestRunner=jest --project-name-and-root-format=derived`
|
||||||
|
);
|
||||||
await updateProjectConfig(lib3, (config) => {
|
await updateProjectConfig(lib3, (config) => {
|
||||||
config.implicitDependencies = [`${lib1}-data-access`];
|
config.implicitDependencies = [`${lib1}-data-access`];
|
||||||
return config;
|
return config;
|
||||||
@ -394,7 +410,7 @@ describe('Workspace Tests', () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
|
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access --project-name-and-root-format=derived`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(moveOutput).toContain(`DELETE packages/${lib1}/data-access`);
|
expect(moveOutput).toContain(`DELETE packages/${lib1}/data-access`);
|
||||||
@ -483,26 +499,27 @@ describe('Workspace Tests', () => {
|
|||||||
const lib1 = uniq('lib1');
|
const lib1 = uniq('lib1');
|
||||||
const lib2 = uniq('lib2');
|
const lib2 = uniq('lib2');
|
||||||
const lib3 = uniq('lib3');
|
const lib3 = uniq('lib3');
|
||||||
runCLI(`generate @nx/js:lib ${lib1} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib1} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/src/lib/${lib1}.ts`,
|
`${lib1}/src/lib/${lib1}.ts`,
|
||||||
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(`${lib1}/src/index.ts`, `export * from './lib/${lib1}.ts'`);
|
||||||
`libs/${lib1}/src/index.ts`,
|
|
||||||
`export * from './lib/${lib1}.ts'`
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a library which imports a class from lib1
|
* Create a library which imports a class from lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib2}-ui --directory=${lib2}/ui --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
`${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
||||||
`import { fromLibOne } from '@${proj}/${lib1}';
|
`import { fromLibOne } from '@${proj}/${lib1}';
|
||||||
|
|
||||||
export const fromLibTwo = () => fromLibOne();`
|
export const fromLibTwo = () => fromLibOne();`
|
||||||
@ -512,7 +529,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which has an implicit dependency on lib1
|
* Create a library which has an implicit dependency on lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib3} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
await updateProjectConfig(lib3, (config) => {
|
await updateProjectConfig(lib3, (config) => {
|
||||||
config.implicitDependencies = [lib1];
|
config.implicitDependencies = [lib1];
|
||||||
return config;
|
return config;
|
||||||
@ -523,13 +542,13 @@ describe('Workspace Tests', () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/workspace:move --project ${lib1} ${lib1}/data-access`
|
`generate @nx/workspace:move --project ${lib1} ${lib1}/data-access --newProjectName=${lib1}-data-access --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(moveOutput).toContain(`DELETE libs/${lib1}/project.json`);
|
expect(moveOutput).toContain(`DELETE ${lib1}/project.json`);
|
||||||
expect(exists(`libs/${lib1}/project.json`)).toBeFalsy();
|
expect(exists(`${lib1}/project.json`)).toBeFalsy();
|
||||||
|
|
||||||
const newPath = `libs/${lib1}/data-access`;
|
const newPath = `${lib1}/data-access`;
|
||||||
const newName = `${lib1}-data-access`;
|
const newName = `${lib1}-data-access`;
|
||||||
|
|
||||||
const readmePath = `${newPath}/README.md`;
|
const readmePath = `${newPath}/README.md`;
|
||||||
@ -541,8 +560,8 @@ describe('Workspace Tests', () => {
|
|||||||
checkFilesExist(jestConfigPath);
|
checkFilesExist(jestConfigPath);
|
||||||
const jestConfig = readFile(jestConfigPath);
|
const jestConfig = readFile(jestConfigPath);
|
||||||
expect(jestConfig).toContain(`displayName: '${lib1}-data-access'`);
|
expect(jestConfig).toContain(`displayName: '${lib1}-data-access'`);
|
||||||
expect(jestConfig).toContain(`preset: '../../../jest.preset.js'`);
|
expect(jestConfig).toContain(`preset: '../../jest.preset.js'`);
|
||||||
expect(jestConfig).toContain(`'../../../coverage/${newPath}'`);
|
expect(jestConfig).toContain(`'../../coverage/${newPath}'`);
|
||||||
|
|
||||||
const tsConfigPath = `${newPath}/tsconfig.json`;
|
const tsConfigPath = `${newPath}/tsconfig.json`;
|
||||||
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
expect(moveOutput).toContain(`CREATE ${tsConfigPath}`);
|
||||||
@ -552,17 +571,13 @@ describe('Workspace Tests', () => {
|
|||||||
expect(moveOutput).toContain(`CREATE ${tsConfigLibPath}`);
|
expect(moveOutput).toContain(`CREATE ${tsConfigLibPath}`);
|
||||||
checkFilesExist(tsConfigLibPath);
|
checkFilesExist(tsConfigLibPath);
|
||||||
const tsConfigLib = readJson(tsConfigLibPath);
|
const tsConfigLib = readJson(tsConfigLibPath);
|
||||||
expect(tsConfigLib.compilerOptions.outDir).toEqual(
|
expect(tsConfigLib.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
'../../../dist/out-tsc'
|
|
||||||
);
|
|
||||||
|
|
||||||
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
const tsConfigSpecPath = `${newPath}/tsconfig.spec.json`;
|
||||||
expect(moveOutput).toContain(`CREATE ${tsConfigSpecPath}`);
|
expect(moveOutput).toContain(`CREATE ${tsConfigSpecPath}`);
|
||||||
checkFilesExist(tsConfigSpecPath);
|
checkFilesExist(tsConfigSpecPath);
|
||||||
const tsConfigSpec = readJson(tsConfigSpecPath);
|
const tsConfigSpec = readJson(tsConfigSpecPath);
|
||||||
expect(tsConfigSpec.compilerOptions.outDir).toEqual(
|
expect(tsConfigSpec.compilerOptions.outDir).toEqual('../../dist/out-tsc');
|
||||||
'../../../dist/out-tsc'
|
|
||||||
);
|
|
||||||
|
|
||||||
const indexPath = `${newPath}/src/index.ts`;
|
const indexPath = `${newPath}/src/index.ts`;
|
||||||
expect(moveOutput).toContain(`CREATE ${indexPath}`);
|
expect(moveOutput).toContain(`CREATE ${indexPath}`);
|
||||||
@ -587,8 +602,8 @@ describe('Workspace Tests', () => {
|
|||||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}`]
|
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}`]
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}-data-access`]
|
||||||
).toEqual([`libs/${lib1}/data-access/src/index.ts`]);
|
).toEqual([`${lib1}/data-access/src/index.ts`]);
|
||||||
|
|
||||||
projects = await readResolvedConfiguration();
|
projects = await readResolvedConfiguration();
|
||||||
expect(projects[lib1]).toBeUndefined();
|
expect(projects[lib1]).toBeUndefined();
|
||||||
@ -596,17 +611,17 @@ describe('Workspace Tests', () => {
|
|||||||
expect(project).toBeTruthy();
|
expect(project).toBeTruthy();
|
||||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||||
`libs/${lib1}/data-access/**/*.ts`,
|
`${lib1}/data-access/**/*.ts`,
|
||||||
`libs/${lib1}/data-access/package.json`,
|
`${lib1}/data-access/package.json`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the import in lib2 has been updated
|
* Check that the import in lib2 has been updated
|
||||||
*/
|
*/
|
||||||
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
const lib2FilePath = `${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
||||||
const lib2File = readFile(lib2FilePath);
|
const lib2File = readFile(lib2FilePath);
|
||||||
expect(lib2File).toContain(
|
expect(lib2File).toContain(
|
||||||
`import { fromLibOne } from '@${proj}/${lib1}/data-access';`
|
`import { fromLibOne } from '@${proj}/${lib1}-data-access';`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -618,22 +633,24 @@ describe('Workspace Tests', () => {
|
|||||||
const lib1 = uniq('mylib');
|
const lib1 = uniq('mylib');
|
||||||
const lib2 = uniq('mylib');
|
const lib2 = uniq('mylib');
|
||||||
const lib3 = uniq('mylib');
|
const lib3 = uniq('mylib');
|
||||||
runCLI(`generate @nx/js:lib ${lib1}/data-access --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib1}-data-access --directory=${lib1}/data-access --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
let rootTsConfig = readJson('tsconfig.base.json');
|
let rootTsConfig = readJson('tsconfig.base.json');
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`@${proj}/${lib1}-data-access`]
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`${lib1}-data-access`]
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
`${lib1}/data-access/src/lib/${lib1}-data-access.ts`,
|
||||||
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
`export function fromLibOne() { console.log('This is completely pointless'); }`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib1}/data-access/src/index.ts`,
|
`${lib1}/data-access/src/index.ts`,
|
||||||
`export * from './lib/${lib1}-data-access.ts'`
|
`export * from './lib/${lib1}-data-access.ts'`
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -641,11 +658,13 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which imports a class from lib1
|
* Create a library which imports a class from lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib2}/ui --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib2}-ui --directory=${lib2}/ui --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
|
|
||||||
updateFile(
|
updateFile(
|
||||||
`libs/${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
`${lib2}/ui/src/lib/${lib2}-ui.ts`,
|
||||||
`import { fromLibOne } from '${lib1}/data-access';
|
`import { fromLibOne } from '${lib1}-data-access';
|
||||||
|
|
||||||
export const fromLibTwo = () => fromLibOne();`
|
export const fromLibTwo = () => fromLibOne();`
|
||||||
);
|
);
|
||||||
@ -654,7 +673,9 @@ describe('Workspace Tests', () => {
|
|||||||
* Create a library which has an implicit dependency on lib1
|
* Create a library which has an implicit dependency on lib1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
runCLI(`generate @nx/js:lib ${lib3} --unitTestRunner=jest`);
|
runCLI(
|
||||||
|
`generate @nx/js:lib ${lib3} --unitTestRunner=jest --project-name-and-root-format=as-provided`
|
||||||
|
);
|
||||||
await updateProjectConfig(lib3, (config) => {
|
await updateProjectConfig(lib3, (config) => {
|
||||||
config.implicitDependencies = [`${lib1}-data-access`];
|
config.implicitDependencies = [`${lib1}-data-access`];
|
||||||
return config;
|
return config;
|
||||||
@ -665,13 +686,13 @@ describe('Workspace Tests', () => {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const moveOutput = runCLI(
|
const moveOutput = runCLI(
|
||||||
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access`
|
`generate @nx/workspace:move --project ${lib1}-data-access shared/${lib1}/data-access --newProjectName=shared-${lib1}-data-access --project-name-and-root-format=as-provided`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(moveOutput).toContain(`DELETE libs/${lib1}/data-access`);
|
expect(moveOutput).toContain(`DELETE ${lib1}/data-access`);
|
||||||
expect(exists(`libs/${lib1}/data-access`)).toBeFalsy();
|
expect(exists(`${lib1}/data-access`)).toBeFalsy();
|
||||||
|
|
||||||
const newPath = `libs/shared/${lib1}/data-access`;
|
const newPath = `shared/${lib1}/data-access`;
|
||||||
const newName = `shared-${lib1}-data-access`;
|
const newName = `shared-${lib1}-data-access`;
|
||||||
|
|
||||||
const readmePath = `${newPath}/README.md`;
|
const readmePath = `${newPath}/README.md`;
|
||||||
@ -698,11 +719,11 @@ describe('Workspace Tests', () => {
|
|||||||
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
expect(moveOutput).toContain('UPDATE tsconfig.base.json');
|
||||||
rootTsConfig = readJson('tsconfig.base.json');
|
rootTsConfig = readJson('tsconfig.base.json');
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`${lib1}-data-access`]
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
expect(
|
expect(
|
||||||
rootTsConfig.compilerOptions.paths[`shared/${lib1}/data-access`]
|
rootTsConfig.compilerOptions.paths[`shared-${lib1}-data-access`]
|
||||||
).toEqual([`libs/shared/${lib1}/data-access/src/index.ts`]);
|
).toEqual([`shared/${lib1}/data-access/src/index.ts`]);
|
||||||
|
|
||||||
const projects = await readResolvedConfiguration();
|
const projects = await readResolvedConfiguration();
|
||||||
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
expect(projects[`${lib1}-data-access`]).toBeUndefined();
|
||||||
@ -710,17 +731,17 @@ describe('Workspace Tests', () => {
|
|||||||
expect(project).toBeTruthy();
|
expect(project).toBeTruthy();
|
||||||
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
expect(project.sourceRoot).toBe(`${newPath}/src`);
|
||||||
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
expect(project.targets.lint.options.lintFilePatterns).toEqual([
|
||||||
`libs/shared/${lib1}/data-access/**/*.ts`,
|
`shared/${lib1}/data-access/**/*.ts`,
|
||||||
`libs/shared/${lib1}/data-access/package.json`,
|
`shared/${lib1}/data-access/package.json`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check that the import in lib2 has been updated
|
* Check that the import in lib2 has been updated
|
||||||
*/
|
*/
|
||||||
const lib2FilePath = `libs/${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
const lib2FilePath = `${lib2}/ui/src/lib/${lib2}-ui.ts`;
|
||||||
const lib2File = readFile(lib2FilePath);
|
const lib2File = readFile(lib2FilePath);
|
||||||
expect(lib2File).toContain(
|
expect(lib2File).toContain(
|
||||||
`import { fromLibOne } from 'shared/${lib1}/data-access';`
|
`import { fromLibOne } from 'shared-${lib1}-data-access';`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -74,7 +74,8 @@
|
|||||||
"factory": "./src/generators/move/compat",
|
"factory": "./src/generators/move/compat",
|
||||||
"schema": "./src/generators/move/schema.json",
|
"schema": "./src/generators/move/schema.json",
|
||||||
"aliases": ["mv"],
|
"aliases": ["mv"],
|
||||||
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration."
|
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration.",
|
||||||
|
"x-deprecated": "Use the `@nx/workspace:move` generator instead. This generator will be removed in Nx v18."
|
||||||
},
|
},
|
||||||
"convert-to-with-mf": {
|
"convert-to-with-mf": {
|
||||||
"factory": "./src/generators/convert-to-with-mf/convert-to-with-mf.compat",
|
"factory": "./src/generators/convert-to-with-mf/convert-to-with-mf.compat",
|
||||||
@ -230,10 +231,11 @@
|
|||||||
"description": "Generate a Remote Angular Module Federation Application."
|
"description": "Generate a Remote Angular Module Federation Application."
|
||||||
},
|
},
|
||||||
"move": {
|
"move": {
|
||||||
"factory": "./src/generators/move/move#angularMoveGenerator",
|
"factory": "./src/generators/move/move#angularMoveGeneratorInternal",
|
||||||
"schema": "./src/generators/move/schema.json",
|
"schema": "./src/generators/move/schema.json",
|
||||||
"aliases": ["mv"],
|
"aliases": ["mv"],
|
||||||
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration."
|
"description": "Moves an Angular application or library to another folder within the workspace and updates the project configuration.",
|
||||||
|
"x-deprecated": "Use the `@nx/workspace:move` generator instead. This generator will be removed in Nx v18."
|
||||||
},
|
},
|
||||||
"convert-to-with-mf": {
|
"convert-to-with-mf": {
|
||||||
"factory": "./src/generators/convert-to-with-mf/convert-to-with-mf",
|
"factory": "./src/generators/convert-to-with-mf/convert-to-with-mf",
|
||||||
|
|||||||
@ -26,6 +26,7 @@
|
|||||||
"./src/utils": "./src/utils/public-api.js",
|
"./src/utils": "./src/utils/public-api.js",
|
||||||
"./plugins/component-testing": "./plugins/component-testing.js",
|
"./plugins/component-testing": "./plugins/component-testing.js",
|
||||||
"./src/generators/utils": "./src/generators/utils/index.js",
|
"./src/generators/utils": "./src/generators/utils/index.js",
|
||||||
|
"./src/generators/move/move-impl": "./src/generators/move/move-impl.js",
|
||||||
"./src/builders/*/schema.json": "./src/builders/*/schema.json",
|
"./src/builders/*/schema.json": "./src/builders/*/schema.json",
|
||||||
"./src/builders/*.impl": "./src/builders/*.impl.js",
|
"./src/builders/*.impl": "./src/builders/*.impl.js",
|
||||||
"./src/executors/*/schema.json": "./src/executors/*/schema.json",
|
"./src/executors/*/schema.json": "./src/executors/*/schema.json",
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
export * from './normalize-schema';
|
|
||||||
export * from './update-module-name';
|
export * from './update-module-name';
|
||||||
export * from './update-ng-package';
|
export * from './update-ng-package';
|
||||||
export * from './update-secondary-entry-points';
|
export * from './update-secondary-entry-points';
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
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,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
4
packages/angular/src/generators/move/lib/types.ts
Normal file
4
packages/angular/src/generators/move/lib/types.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export type MoveImplOptions = {
|
||||||
|
oldProjectName: string;
|
||||||
|
newProjectName: string;
|
||||||
|
};
|
||||||
@ -1,301 +0,0 @@
|
|||||||
import { Tree } from '@nx/devkit';
|
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
||||||
import { Linter } from '@nx/linter';
|
|
||||||
import { moveGenerator } from '@nx/workspace/generators';
|
|
||||||
import { UnitTestRunner } from '../../../utils/test-runners';
|
|
||||||
import { generateTestLibrary } from '../../utils/testing';
|
|
||||||
import { NormalizedSchema } from '../schema';
|
|
||||||
import { updateModuleName } from './update-module-name';
|
|
||||||
|
|
||||||
describe('updateModuleName Rule', () => {
|
|
||||||
let tree: Tree;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should handle nesting resulting in the same project name', async () => {
|
|
||||||
const updatedModulePath = '/libs/my/first/src/lib/my-first.module.ts';
|
|
||||||
await generateTestLibrary(tree, {
|
|
||||||
name: 'my-first',
|
|
||||||
simpleName: true,
|
|
||||||
});
|
|
||||||
const schema: NormalizedSchema = {
|
|
||||||
projectName: 'my-first',
|
|
||||||
destination: 'my/first',
|
|
||||||
updateImportPath: true,
|
|
||||||
newProjectName: 'my-first',
|
|
||||||
oldProjectRoot: 'my-first',
|
|
||||||
};
|
|
||||||
await moveGenerator(tree, schema);
|
|
||||||
|
|
||||||
updateModuleName(tree, { ...schema, destination: 'my/first' });
|
|
||||||
|
|
||||||
expect(tree.exists(updatedModulePath)).toBe(true);
|
|
||||||
const moduleFile = tree.read(updatedModulePath, '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';
|
|
||||||
const updatedModuleSpecPath =
|
|
||||||
'/libs/shared/my-first/src/lib/shared-my-first.module.spec.ts';
|
|
||||||
const indexPath = '/libs/shared/my-first/src/index.ts';
|
|
||||||
const secondModulePath = 'my-second/src/lib/my-second.module.ts';
|
|
||||||
|
|
||||||
const schema: NormalizedSchema = {
|
|
||||||
projectName: 'my-first',
|
|
||||||
destination: 'shared/my-first',
|
|
||||||
updateImportPath: true,
|
|
||||||
newProjectName: 'shared-my-first',
|
|
||||||
oldProjectRoot: 'my-first',
|
|
||||||
};
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await generateTestLibrary(tree, {
|
|
||||||
name: 'my-first',
|
|
||||||
buildable: false,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
publishable: false,
|
|
||||||
simpleName: true,
|
|
||||||
skipFormat: false,
|
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
});
|
|
||||||
await generateTestLibrary(tree, {
|
|
||||||
name: 'my-second',
|
|
||||||
buildable: false,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
publishable: false,
|
|
||||||
simpleName: true,
|
|
||||||
skipFormat: false,
|
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
});
|
|
||||||
tree.write(
|
|
||||||
'my-first/src/lib/my-first.module.ts',
|
|
||||||
`import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
|
|
||||||
@NgModule({
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
|
||||||
export class MyFirstModule {}`
|
|
||||||
);
|
|
||||||
|
|
||||||
tree.write(
|
|
||||||
'my-first/src/lib/my-first.module.spec.ts',
|
|
||||||
`import { async, TestBed } from '@angular/core/testing';
|
|
||||||
import { MyFirstModule } from './my-first.module';
|
|
||||||
|
|
||||||
describe('MyFirstModule', () => {
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [MyFirstModule]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(MyFirstModule).toBeDefined();
|
|
||||||
});
|
|
||||||
});`
|
|
||||||
);
|
|
||||||
tree.write(
|
|
||||||
secondModulePath,
|
|
||||||
`import { MyFirstModule } from '@proj/my-first';
|
|
||||||
|
|
||||||
export class MySecondModule extends MyFirstModule {}
|
|
||||||
`
|
|
||||||
);
|
|
||||||
await moveGenerator(tree, schema);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should rename the module files and update the module name', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
expect(tree.exists(updatedModulePath)).toBe(true);
|
|
||||||
expect(tree.exists(updatedModuleSpecPath)).toBe(true);
|
|
||||||
|
|
||||||
const moduleFile = tree.read(updatedModulePath, 'utf-8');
|
|
||||||
expect(moduleFile).toContain(`export class SharedMyFirstModule {}`);
|
|
||||||
|
|
||||||
const moduleSpecFile = tree.read(updatedModuleSpecPath, 'utf-8');
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`import { SharedMyFirstModule } from './shared-my-first.module';`
|
|
||||||
);
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`describe('SharedMyFirstModule', () => {`
|
|
||||||
);
|
|
||||||
expect(moduleSpecFile).toContain(`imports: [SharedMyFirstModule]`);
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`expect(SharedMyFirstModule).toBeDefined();`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update any references to the module', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
const importerFile = tree.read(secondModulePath, 'utf-8');
|
|
||||||
expect(importerFile).toContain(
|
|
||||||
`import { SharedMyFirstModule } from '@proj/shared/my-first';`
|
|
||||||
);
|
|
||||||
expect(importerFile).toContain(
|
|
||||||
`export class MySecondModule extends SharedMyFirstModule {}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the index.ts file which exports the module', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
const indexFile = tree.read(indexPath, 'utf-8');
|
|
||||||
expect(indexFile).toContain(
|
|
||||||
`export * from './lib/shared-my-first.module';`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('rename', () => {
|
|
||||||
const schema: NormalizedSchema = {
|
|
||||||
projectName: 'my-source',
|
|
||||||
destination: 'my-destination',
|
|
||||||
updateImportPath: true,
|
|
||||||
newProjectName: 'my-destination',
|
|
||||||
oldProjectRoot: 'my-source',
|
|
||||||
};
|
|
||||||
|
|
||||||
const modulePath = 'my-destination/src/lib/my-destination.module.ts';
|
|
||||||
const moduleSpecPath =
|
|
||||||
'my-destination/src/lib/my-destination.module.spec.ts';
|
|
||||||
const indexPath = 'my-destination/src/index.ts';
|
|
||||||
const importerPath = 'my-importer/src/lib/my-importing-file.ts';
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
// fake a mid-move tree:
|
|
||||||
await generateTestLibrary(tree, {
|
|
||||||
name: 'my-destination',
|
|
||||||
buildable: false,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
publishable: false,
|
|
||||||
simpleName: true,
|
|
||||||
skipFormat: false,
|
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
});
|
|
||||||
|
|
||||||
tree.write(
|
|
||||||
'my-destination/src/lib/my-source.module.ts',
|
|
||||||
`import { NgModule } from '@angular/core';
|
|
||||||
import { CommonModule } from '@angular/common';
|
|
||||||
@NgModule({
|
|
||||||
imports: [CommonModule]
|
|
||||||
})
|
|
||||||
export class MySourceModule {}`
|
|
||||||
);
|
|
||||||
|
|
||||||
tree.write(
|
|
||||||
'my-destination/src/lib/my-source.module.spec.ts',
|
|
||||||
`import { async, TestBed } from '@angular/core/testing';
|
|
||||||
import { MySourceModule } from './my-source.module';
|
|
||||||
describe('MySourceModule', () => {
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
imports: [MySourceModule]
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
it('should create', () => {
|
|
||||||
expect(MySourceModule).toBeDefined();
|
|
||||||
});
|
|
||||||
});`
|
|
||||||
);
|
|
||||||
|
|
||||||
tree.write(
|
|
||||||
indexPath,
|
|
||||||
`export * from './lib/my-source.module';
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
tree.delete(modulePath);
|
|
||||||
tree.delete(moduleSpecPath);
|
|
||||||
|
|
||||||
await generateTestLibrary(tree, {
|
|
||||||
name: 'my-importer',
|
|
||||||
buildable: false,
|
|
||||||
linter: Linter.EsLint,
|
|
||||||
publishable: false,
|
|
||||||
simpleName: true,
|
|
||||||
skipFormat: false,
|
|
||||||
unitTestRunner: UnitTestRunner.Jest,
|
|
||||||
});
|
|
||||||
|
|
||||||
tree.write(
|
|
||||||
importerPath,
|
|
||||||
`import { MySourceModule } from '@proj/my-destination';
|
|
||||||
export class MyExtendedSourceModule extends MySourceModule {}
|
|
||||||
`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should rename the module files and update the module name', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
expect(tree.exists(modulePath)).toBe(true);
|
|
||||||
expect(tree.exists(moduleSpecPath)).toBe(true);
|
|
||||||
|
|
||||||
const moduleFile = tree.read(modulePath, 'utf-8');
|
|
||||||
expect(moduleFile).toContain(`export class MyDestinationModule {}`);
|
|
||||||
|
|
||||||
const moduleSpecFile = tree.read(moduleSpecPath, 'utf-8');
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`import { MyDestinationModule } from './my-destination.module';`
|
|
||||||
);
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`describe('MyDestinationModule', () => {`
|
|
||||||
);
|
|
||||||
expect(moduleSpecFile).toContain(`imports: [MyDestinationModule]`);
|
|
||||||
expect(moduleSpecFile).toContain(
|
|
||||||
`expect(MyDestinationModule).toBeDefined();`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update any references to the module', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
const importerFile = tree.read(importerPath, 'utf-8');
|
|
||||||
expect(importerFile).toContain(
|
|
||||||
`import { MyDestinationModule } from '@proj/my-destination';`
|
|
||||||
);
|
|
||||||
expect(importerFile).toContain(
|
|
||||||
`export class MyExtendedSourceModule extends MyDestinationModule {}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should update the index.ts file which exports the module', async () => {
|
|
||||||
updateModuleName(tree, schema);
|
|
||||||
|
|
||||||
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(
|
|
||||||
'my-source-demo/src/lib/my-source-demo.module.ts',
|
|
||||||
'utf-8'
|
|
||||||
);
|
|
||||||
expect(moduleFile).toContain(`export class MySourceDemoModule {}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -7,7 +7,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
visitNotIgnoredFiles,
|
visitNotIgnoredFiles,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import type { NormalizedSchema } from '../schema';
|
import type { MoveImplOptions } from './types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,8 +19,16 @@ import type { NormalizedSchema } from '../schema';
|
|||||||
*/
|
*/
|
||||||
export function updateModuleName(
|
export function updateModuleName(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
{ projectName: oldProjectName, newProjectName }: NormalizedSchema
|
{ oldProjectName, newProjectName }: MoveImplOptions
|
||||||
): void {
|
): void {
|
||||||
|
const unscopedNewProjectName = newProjectName.startsWith('@')
|
||||||
|
? newProjectName.split('/')[1]
|
||||||
|
: newProjectName;
|
||||||
|
|
||||||
|
if (oldProjectName === unscopedNewProjectName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, newProjectName);
|
const project = readProjectConfiguration(tree, newProjectName);
|
||||||
|
|
||||||
if (project.projectType === 'application') {
|
if (project.projectType === 'application') {
|
||||||
@ -31,14 +39,14 @@ export function updateModuleName(
|
|||||||
|
|
||||||
const moduleName = {
|
const moduleName = {
|
||||||
from: `${names(oldProjectName).className}Module`,
|
from: `${names(oldProjectName).className}Module`,
|
||||||
to: `${names(newProjectName).className}Module`,
|
to: `${names(unscopedNewProjectName).className}Module`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const findModuleName = new RegExp(`\\b${moduleName.from}`, 'g');
|
const findModuleName = new RegExp(`\\b${moduleName.from}`, 'g');
|
||||||
|
|
||||||
const moduleFile = {
|
const moduleFile = {
|
||||||
from: `${oldProjectName}.module`,
|
from: `${oldProjectName}.module`,
|
||||||
to: `${newProjectName}.module`,
|
to: `${unscopedNewProjectName}.module`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const findFileName = new RegExp(`\\b${moduleFile.from}`, 'g');
|
const findFileName = new RegExp(`\\b${moduleFile.from}`, 'g');
|
||||||
|
|||||||
@ -7,9 +7,9 @@ import {
|
|||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { join, relative } from 'path';
|
import { join, relative } from 'path';
|
||||||
import type { NormalizedSchema } from '../schema';
|
import type { MoveImplOptions } from './types';
|
||||||
|
|
||||||
export function updateNgPackage(tree: Tree, schema: NormalizedSchema): void {
|
export function updateNgPackage(tree: Tree, schema: MoveImplOptions): void {
|
||||||
const project = readProjectConfiguration(tree, schema.newProjectName);
|
const project = readProjectConfiguration(tree, schema.newProjectName);
|
||||||
|
|
||||||
if (project.projectType === 'application') {
|
if (project.projectType === 'application') {
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
visitNotIgnoredFiles,
|
visitNotIgnoredFiles,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { basename, dirname } from 'path';
|
import { basename, dirname } from 'path';
|
||||||
import type { NormalizedSchema } from '../schema';
|
import type { MoveImplOptions } from './types';
|
||||||
|
|
||||||
const libraryExecutors = [
|
const libraryExecutors = [
|
||||||
'@angular-devkit/build-angular:ng-packagr',
|
'@angular-devkit/build-angular:ng-packagr',
|
||||||
@ -19,8 +19,12 @@ const libraryExecutors = [
|
|||||||
|
|
||||||
export function updateSecondaryEntryPoints(
|
export function updateSecondaryEntryPoints(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: NormalizedSchema
|
schema: MoveImplOptions
|
||||||
): void {
|
): void {
|
||||||
|
if (schema.oldProjectName === schema.newProjectName) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, schema.newProjectName);
|
const project = readProjectConfiguration(tree, schema.newProjectName);
|
||||||
|
|
||||||
if (project.projectType !== 'library') {
|
if (project.projectType !== 'library') {
|
||||||
@ -47,7 +51,7 @@ export function updateSecondaryEntryPoints(
|
|||||||
updateReadme(
|
updateReadme(
|
||||||
tree,
|
tree,
|
||||||
dirname(filePath),
|
dirname(filePath),
|
||||||
schema.projectName,
|
schema.oldProjectName,
|
||||||
schema.newProjectName
|
schema.newProjectName
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
35
packages/angular/src/generators/move/move-impl.ts
Normal file
35
packages/angular/src/generators/move/move-impl.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { createProjectGraphAsync, type Tree } from '@nx/devkit';
|
||||||
|
import {
|
||||||
|
updateModuleName,
|
||||||
|
updateNgPackage,
|
||||||
|
updateSecondaryEntryPoints,
|
||||||
|
} from './lib';
|
||||||
|
import type { MoveImplOptions } from './lib/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Angular-specific logic to move a project to another directory.
|
||||||
|
* This is invoked by the `@nx/workspace:move` generator.
|
||||||
|
*/
|
||||||
|
export async function move(
|
||||||
|
tree: Tree,
|
||||||
|
options: MoveImplOptions
|
||||||
|
): Promise<void> {
|
||||||
|
// while the project has already being moved at this point, the changes are
|
||||||
|
// still in the virtual tree and haven't been committed, so the project graph
|
||||||
|
// still contains the old project name
|
||||||
|
if (!(await isAngularProject(options.oldProjectName))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateModuleName(tree, options);
|
||||||
|
updateNgPackage(tree, options);
|
||||||
|
updateSecondaryEntryPoints(tree, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isAngularProject(project: string): Promise<boolean> {
|
||||||
|
const projectGraph = await createProjectGraphAsync();
|
||||||
|
|
||||||
|
return projectGraph.dependencies[project]?.some(
|
||||||
|
(dependency) => dependency.target === 'npm:@angular/core'
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,20 +1,38 @@
|
|||||||
import * as devkit from '@nx/devkit';
|
import * as devkit from '@nx/devkit';
|
||||||
import { readJson, Tree } from '@nx/devkit';
|
import { ProjectGraph, 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 { 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';
|
||||||
|
|
||||||
describe('@nx/angular:move', () => {
|
describe('@nx/angular:move', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
|
let projectGraph: ProjectGraph;
|
||||||
|
|
||||||
|
function addProjectToGraph(project: string): void {
|
||||||
|
projectGraph = {
|
||||||
|
dependencies: {
|
||||||
|
[project]: [
|
||||||
|
{ source: project, target: 'npm:@angular/core', type: 'static' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
nodes: {
|
||||||
|
[project]: {
|
||||||
|
name: project,
|
||||||
|
type: 'lib',
|
||||||
|
data: { root: project, targets: {} },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
|
|
||||||
await generateTestLibrary(tree, {
|
await generateTestLibrary(tree, {
|
||||||
name: 'mylib',
|
name: 'my-lib',
|
||||||
buildable: false,
|
buildable: false,
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
publishable: false,
|
publishable: false,
|
||||||
@ -23,32 +41,38 @@ describe('@nx/angular:move', () => {
|
|||||||
unitTestRunner: UnitTestRunner.Jest,
|
unitTestRunner: UnitTestRunner.Jest,
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.clearAllMocks();
|
jest
|
||||||
|
.spyOn(devkit, 'createProjectGraphAsync')
|
||||||
|
.mockImplementation(() => Promise.resolve(projectGraph));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should move a project', async () => {
|
it('should move a project', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
await angularMoveGenerator(tree, {
|
await angularMoveGenerator(tree, {
|
||||||
projectName: 'mylib',
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'mynewlib',
|
||||||
destination: 'mynewlib',
|
destination: 'mynewlib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(tree.exists('libs/mynewlib/src/lib/mynewlib.module.ts')).toEqual(
|
expect(tree.exists('mynewlib/src/lib/mynewlib.module.ts')).toEqual(true);
|
||||||
true
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update ng-package.json dest property', async () => {
|
it('should update ng-package.json dest property', async () => {
|
||||||
await generateTestLibrary(tree, { name: 'mylib2', buildable: true });
|
await generateTestLibrary(tree, { name: 'mylib2', buildable: true });
|
||||||
|
addProjectToGraph('mylib2');
|
||||||
|
|
||||||
await angularMoveGenerator(tree, {
|
await angularMoveGenerator(tree, {
|
||||||
projectName: 'mylib2',
|
projectName: 'mylib2',
|
||||||
destination: 'mynewlib2',
|
destination: 'mynewlib2',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
const ngPackageJson = readJson(tree, 'libs/mynewlib2/ng-package.json');
|
const ngPackageJson = readJson(tree, 'mynewlib2/ng-package.json');
|
||||||
expect(ngPackageJson.dest).toEqual('../../dist/libs/mynewlib2');
|
expect(ngPackageJson.dest).toEqual('../dist/mynewlib2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update secondary entry points readme file', async () => {
|
it('should update secondary entry points readme file', async () => {
|
||||||
@ -57,14 +81,17 @@ describe('@nx/angular:move', () => {
|
|||||||
library: 'mylib2',
|
library: 'mylib2',
|
||||||
name: 'testing',
|
name: 'testing',
|
||||||
});
|
});
|
||||||
|
addProjectToGraph('mylib2');
|
||||||
|
|
||||||
await angularMoveGenerator(tree, {
|
await angularMoveGenerator(tree, {
|
||||||
projectName: 'mylib2',
|
projectName: 'mylib2',
|
||||||
|
newProjectName: 'mynewlib2',
|
||||||
destination: 'mynewlib2',
|
destination: 'mynewlib2',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
const readme = tree.read('libs/mynewlib2/testing/README.md', 'utf-8');
|
const readme = tree.read('mynewlib2/testing/README.md', 'utf-8');
|
||||||
expect(readme).toMatchInlineSnapshot(`
|
expect(readme).toMatchInlineSnapshot(`
|
||||||
"# @proj/mynewlib2/testing
|
"# @proj/mynewlib2/testing
|
||||||
|
|
||||||
@ -73,28 +100,275 @@ describe('@nx/angular:move', () => {
|
|||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should format files', async () => {
|
it('should handle nesting resulting in the same project name', async () => {
|
||||||
jest.spyOn(devkit, 'formatFiles');
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
await angularMoveGenerator(tree, {
|
await angularMoveGenerator(tree, {
|
||||||
projectName: 'mylib',
|
projectName: 'my-lib',
|
||||||
destination: 'mynewlib',
|
destination: 'my/lib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(devkit.formatFiles).toHaveBeenCalled();
|
expect(tree.exists('my/lib/src/lib/my-lib.module.ts')).toBe(true);
|
||||||
|
const moduleFile = tree.read('my/lib/src/lib/my-lib.module.ts', 'utf-8');
|
||||||
|
expect(moduleFile).toContain(`export class MyLibModule {}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not format files when --skipFormat=true', async () => {
|
describe('move to subfolder', () => {
|
||||||
jest.spyOn(devkit, 'formatFiles');
|
beforeEach(async () => {
|
||||||
|
await generateTestLibrary(tree, {
|
||||||
|
name: 'my-lib2',
|
||||||
|
buildable: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
publishable: false,
|
||||||
|
simpleName: true,
|
||||||
|
skipFormat: false,
|
||||||
|
unitTestRunner: UnitTestRunner.Jest,
|
||||||
|
});
|
||||||
|
tree.write(
|
||||||
|
'my-lib/src/lib/my-lib.module.ts',
|
||||||
|
`import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule]
|
||||||
|
})
|
||||||
|
export class MyLibModule {}`
|
||||||
|
);
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'my-lib/src/lib/my-lib.module.spec.ts',
|
||||||
|
`import { async, TestBed } from '@angular/core/testing';
|
||||||
|
import { MyLibModule } from './my-lib.module';
|
||||||
|
|
||||||
|
describe('MyLibModule', () => {
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [MyLibModule]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(MyLibModule).toBeDefined();
|
||||||
|
});
|
||||||
|
});`
|
||||||
|
);
|
||||||
|
tree.write(
|
||||||
|
'my-lib2/src/lib/my-lib2.module.ts',
|
||||||
|
`import { MyLibModule } from '@proj/my-lib';
|
||||||
|
|
||||||
|
export class MyLib2Module extends MyLibModule {}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rename the module files and update the module name', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
await angularMoveGenerator(tree, {
|
await angularMoveGenerator(tree, {
|
||||||
projectName: 'mylib',
|
projectName: 'my-lib',
|
||||||
destination: 'mynewlib',
|
newProjectName: 'shared-my-lib',
|
||||||
|
destination: 'shared/my-lib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
skipFormat: true,
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(devkit.formatFiles).not.toHaveBeenCalled();
|
expect(tree.exists('shared/my-lib/src/lib/shared-my-lib.module.ts')).toBe(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
tree.exists('shared/my-lib/src/lib/shared-my-lib.module.spec.ts')
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
const moduleFile = tree.read(
|
||||||
|
'shared/my-lib/src/lib/shared-my-lib.module.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(moduleFile).toContain(`export class SharedMyLibModule {}`);
|
||||||
|
|
||||||
|
const moduleSpecFile = tree.read(
|
||||||
|
'shared/my-lib/src/lib/shared-my-lib.module.spec.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(moduleSpecFile).toContain(
|
||||||
|
`import { SharedMyLibModule } from './shared-my-lib.module';`
|
||||||
|
);
|
||||||
|
expect(moduleSpecFile).toContain(`describe('SharedMyLibModule', () => {`);
|
||||||
|
expect(moduleSpecFile).toContain(`imports: [SharedMyLibModule]`);
|
||||||
|
expect(moduleSpecFile).toContain(
|
||||||
|
`expect(SharedMyLibModule).toBeDefined();`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update any references to the module', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'shared-my-lib',
|
||||||
|
destination: 'shared/my-lib',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const importerFile = tree.read(
|
||||||
|
'my-lib2/src/lib/my-lib2.module.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(importerFile).toContain(
|
||||||
|
`import { SharedMyLibModule } from '@proj/shared-my-lib';`
|
||||||
|
);
|
||||||
|
expect(importerFile).toContain(
|
||||||
|
`export class MyLib2Module extends SharedMyLibModule {}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the index.ts file which exports the module', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'shared-my-lib',
|
||||||
|
destination: 'shared/my-lib',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const indexFile = tree.read('shared/my-lib/src/index.ts', 'utf-8');
|
||||||
|
expect(indexFile).toContain(
|
||||||
|
`export * from './lib/shared-my-lib.module';`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('rename', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await generateTestLibrary(tree, {
|
||||||
|
name: 'my-importer',
|
||||||
|
buildable: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
publishable: false,
|
||||||
|
simpleName: true,
|
||||||
|
skipFormat: false,
|
||||||
|
unitTestRunner: UnitTestRunner.Jest,
|
||||||
|
});
|
||||||
|
|
||||||
|
tree.write(
|
||||||
|
'my-importer/src/lib/my-importing-file.ts',
|
||||||
|
`import { MyLibModule } from '@proj/my-lib';
|
||||||
|
export class MyExtendedLibModule extends MyLibModule {}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should rename the module file and update the module name', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'my-destination',
|
||||||
|
destination: 'my-destination',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(
|
||||||
|
tree.exists('my-destination/src/lib/my-destination.module.ts')
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
const moduleFile = tree.read(
|
||||||
|
'my-destination/src/lib/my-destination.module.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(moduleFile).toContain(`export class MyDestinationModule {}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update any references to the module', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'my-destination',
|
||||||
|
destination: 'my-destination',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const importerFile = tree.read(
|
||||||
|
'my-importer/src/lib/my-importing-file.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(importerFile).toContain(
|
||||||
|
`import { MyDestinationModule } from '@proj/my-destination';`
|
||||||
|
);
|
||||||
|
expect(importerFile).toContain(
|
||||||
|
`export class MyExtendedLibModule extends MyDestinationModule {}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the index.ts file which exports the module', async () => {
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'my-destination',
|
||||||
|
destination: 'my-destination',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const indexFile = tree.read('my-destination/src/index.ts', '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-lib-demo',
|
||||||
|
buildable: false,
|
||||||
|
linter: Linter.EsLint,
|
||||||
|
publishable: false,
|
||||||
|
simpleName: true,
|
||||||
|
skipFormat: false,
|
||||||
|
unitTestRunner: UnitTestRunner.Jest,
|
||||||
|
});
|
||||||
|
addProjectToGraph('my-lib');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
newProjectName: 'my-destination',
|
||||||
|
destination: 'my-destination',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
|
const moduleFile = tree.read(
|
||||||
|
'my-lib-demo/src/lib/my-lib-demo.module.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(moduleFile).toContain(`export class MyLibDemoModule {}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should move project correctly when --project-name-and-root-format=derived', async () => {
|
||||||
|
await generateTestLibrary(tree, { name: 'mylib2', buildable: true });
|
||||||
|
addProjectToGraph('mylib2');
|
||||||
|
|
||||||
|
await angularMoveGenerator(tree, {
|
||||||
|
projectName: 'mylib2',
|
||||||
|
destination: 'mynewlib',
|
||||||
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.exists('libs/mynewlib/src/lib/mynewlib.module.ts')).toEqual(
|
||||||
|
true
|
||||||
|
);
|
||||||
|
const ngPackageJson = readJson(tree, 'libs/mynewlib/ng-package.json');
|
||||||
|
expect(ngPackageJson.dest).toEqual('../../dist/libs/mynewlib');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,32 +1,21 @@
|
|||||||
import { formatFiles, Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import { moveGenerator } from '@nx/workspace/generators';
|
import { moveGeneratorInternal } from '@nx/workspace/src/generators/move/move';
|
||||||
import {
|
|
||||||
normalizeSchema,
|
|
||||||
updateModuleName,
|
|
||||||
updateNgPackage,
|
|
||||||
updateSecondaryEntryPoints,
|
|
||||||
} from './lib';
|
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves an Angular lib/app to another folder (and renames it in the process)
|
|
||||||
*
|
|
||||||
* @remarks It's important to note that `updateModuleName` is done after the update
|
|
||||||
* to the workspace, so it can't use the same tricks as the `@nx/workspace` rules
|
|
||||||
* to get the before and after names and paths.
|
|
||||||
*/
|
|
||||||
export async function angularMoveGenerator(
|
export async function angularMoveGenerator(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: Schema
|
schema: Schema
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const normalizedSchema = normalizeSchema(tree, schema);
|
await angularMoveGeneratorInternal(tree, {
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
await moveGenerator(tree, { ...schema, skipFormat: true });
|
...schema,
|
||||||
updateModuleName(tree, normalizedSchema);
|
});
|
||||||
updateNgPackage(tree, normalizedSchema);
|
|
||||||
updateSecondaryEntryPoints(tree, normalizedSchema);
|
|
||||||
|
|
||||||
if (!normalizedSchema.skipFormat) {
|
|
||||||
await formatFiles(tree);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function angularMoveGeneratorInternal(
|
||||||
|
tree: Tree,
|
||||||
|
schema: Schema
|
||||||
|
): Promise<void> {
|
||||||
|
process.env.NX_ANGULAR_MOVE_INVOKED = 'true';
|
||||||
|
await moveGeneratorInternal(tree, schema);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
|
import { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
destination: string;
|
destination: string;
|
||||||
updateImportPath: boolean;
|
updateImportPath: boolean;
|
||||||
importPath?: string;
|
importPath?: string;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
}
|
newProjectName?: string;
|
||||||
|
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||||
export interface NormalizedSchema extends Schema {
|
|
||||||
oldProjectRoot: string;
|
|
||||||
newProjectName: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,13 @@
|
|||||||
"x-dropdown": "projects",
|
"x-dropdown": "projects",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"newProjectName": {
|
||||||
|
"type": "string",
|
||||||
|
"alias": "project",
|
||||||
|
"description": "The new name of the project after the move.",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"destination": {
|
"destination": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The folder to move the Angular project into.",
|
"description": "The folder to move the Angular project into.",
|
||||||
@ -28,6 +35,11 @@
|
|||||||
},
|
},
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"projectNameAndRootFormat": {
|
||||||
|
"description": "Whether to generate the new project name and destination as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["as-provided", "derived"]
|
||||||
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The new import path to use in the `tsconfig.base.json`."
|
"description": "The new import path to use in the `tsconfig.base.json`."
|
||||||
|
|||||||
@ -47,7 +47,7 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"move": {
|
"move": {
|
||||||
"factory": "./src/generators/move/move#moveGenerator",
|
"factory": "./src/generators/move/move#moveGeneratorInternal",
|
||||||
"schema": "./src/generators/move/schema.json",
|
"schema": "./src/generators/move/schema.json",
|
||||||
"aliases": ["mv"],
|
"aliases": ["mv"],
|
||||||
"description": "Move an application or library to another folder."
|
"description": "Move an application or library to another folder."
|
||||||
|
|||||||
@ -61,12 +61,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@nx/devkit": "file:../devkit",
|
||||||
"chalk": "^4.1.0",
|
"chalk": "^4.1.0",
|
||||||
|
"enquirer": "~2.3.6",
|
||||||
"ignore": "^5.0.4",
|
"ignore": "^5.0.4",
|
||||||
"rxjs": "^7.8.0",
|
"rxjs": "^7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"yargs-parser": "21.1.1",
|
"yargs-parser": "21.1.1"
|
||||||
"@nx/devkit": "file:../devkit"
|
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|||||||
@ -45,8 +45,8 @@ export async function monorepoGenerator(tree: Tree, options: {}) {
|
|||||||
libsDir,
|
libsDir,
|
||||||
project.root === '.' ? project.name : project.root
|
project.root === '.' ? project.name : project.root
|
||||||
),
|
),
|
||||||
destinationRelativeToRoot: true,
|
|
||||||
updateImportPath: project.projectType === 'library',
|
updateImportPath: project.projectType === 'library',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Schema } from '../schema';
|
import { NormalizedSchema } from '../schema';
|
||||||
import { checkDestination } from './check-destination';
|
import { checkDestination } from './check-destination';
|
||||||
|
|
||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
@ -16,20 +16,24 @@ describe('checkDestination', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if the path is not explicit', async () => {
|
it('should throw an error if the path is not explicit', async () => {
|
||||||
const schema: Schema = {
|
const schema: NormalizedSchema = {
|
||||||
projectName: 'my-lib',
|
projectName: 'my-lib',
|
||||||
destination: '../apps/not-an-app',
|
destination: '../apps/not-an-app',
|
||||||
importPath: undefined,
|
importPath: undefined,
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
relativeToRootDestination: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkDestination(tree, schema, projectConfig);
|
checkDestination(tree, schema, schema.destination);
|
||||||
}).toThrow(
|
}).toThrow(
|
||||||
`Invalid destination: [${schema.destination}] - Please specify explicit path.`
|
`Invalid destination: [${schema.destination}] - Please specify explicit path.`
|
||||||
);
|
);
|
||||||
@ -38,32 +42,35 @@ describe('checkDestination', () => {
|
|||||||
it('should throw an error if the path already exists', async () => {
|
it('should throw an error if the path already exists', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-other-lib',
|
name: 'my-other-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
const schema: Schema = {
|
const schema: NormalizedSchema = {
|
||||||
projectName: 'my-lib',
|
projectName: 'my-lib',
|
||||||
destination: 'my-other-lib',
|
destination: 'my-other-lib',
|
||||||
importPath: undefined,
|
importPath: undefined,
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
relativeToRootDestination: 'my-other-lib',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkDestination(tree, schema, projectConfig);
|
checkDestination(tree, schema, schema.destination);
|
||||||
}).toThrow(
|
}).toThrow(
|
||||||
`Invalid destination: [${schema.destination}] - Path is not empty.`
|
`Invalid destination: [${schema.destination}] - Path is not empty.`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT throw an error if the path is available', async () => {
|
it('should NOT throw an error if the path is available', async () => {
|
||||||
const schema: Schema = {
|
const schema: NormalizedSchema = {
|
||||||
projectName: 'my-lib',
|
projectName: 'my-lib',
|
||||||
destination: 'my-other-lib',
|
destination: 'my-other-lib',
|
||||||
importPath: undefined,
|
importPath: undefined,
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
relativeToRootDestination: 'my-other-lib',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(() => {
|
expect(() => {
|
||||||
checkDestination(tree, schema, projectConfig);
|
checkDestination(tree, schema, schema.destination);
|
||||||
}).not.toThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { ProjectConfiguration, Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import { Schema } from '../schema';
|
import type { NormalizedSchema } from '../schema';
|
||||||
import { getDestination } from './utils';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the destination folder is valid
|
* Checks whether the destination folder is valid
|
||||||
@ -12,18 +11,16 @@ import { getDestination } from './utils';
|
|||||||
*/
|
*/
|
||||||
export function checkDestination(
|
export function checkDestination(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: Schema,
|
schema: NormalizedSchema,
|
||||||
projectConfig: ProjectConfiguration
|
providedDestination: string
|
||||||
) {
|
) {
|
||||||
const INVALID_DESTINATION = `Invalid destination: [${schema.destination}]`;
|
const INVALID_DESTINATION = `Invalid destination: [${providedDestination}]`;
|
||||||
|
|
||||||
if (schema.destination.includes('..')) {
|
if (providedDestination.includes('..')) {
|
||||||
throw new Error(`${INVALID_DESTINATION} - Please specify explicit path.`);
|
throw new Error(`${INVALID_DESTINATION} - Please specify explicit path.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const destination = getDestination(tree, schema, projectConfig);
|
if (tree.children(schema.relativeToRootDestination).length > 0) {
|
||||||
|
|
||||||
if (tree.children(destination).length > 0) {
|
|
||||||
throw new Error(`${INVALID_DESTINATION} - Path is not empty.`);
|
throw new Error(`${INVALID_DESTINATION} - Path is not empty.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,10 @@ describe('moveProject', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -27,14 +30,13 @@ describe('moveProject', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
moveProjectFiles(tree, schema, projectConfig);
|
moveProjectFiles(tree, schema, projectConfig);
|
||||||
|
|
||||||
const destinationChildren = tree.children('libs/my-destination');
|
const destinationChildren = tree.children('my-destination');
|
||||||
expect(destinationChildren.length).toBeGreaterThan(0);
|
expect(destinationChildren.length).toBeGreaterThan(0);
|
||||||
expect(tree.exists('libs/my-lib')).toBeFalsy();
|
expect(tree.exists('my-lib')).toBeFalsy();
|
||||||
expect(tree.children('libs')).not.toContain('my-lib');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,7 +31,7 @@ describe('normalizeSchema', () => {
|
|||||||
projectConfiguration = readProjectConfiguration(tree, schema.projectName);
|
projectConfiguration = readProjectConfiguration(tree, schema.projectName);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should calculate importPath, projectName and relativeToRootDestination correctly', () => {
|
it('should calculate importPath, projectName and relativeToRootDestination correctly', async () => {
|
||||||
const expected: NormalizedSchema = {
|
const expected: NormalizedSchema = {
|
||||||
destination: 'my/library',
|
destination: 'my/library',
|
||||||
importPath: '@proj/my/library',
|
importPath: '@proj/my/library',
|
||||||
@ -41,12 +41,12 @@ describe('normalizeSchema', () => {
|
|||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = normalizeSchema(tree, schema, projectConfiguration);
|
const result = await normalizeSchema(tree, schema, projectConfiguration);
|
||||||
|
|
||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should normalize destination and derive projectName correctly', () => {
|
it('should normalize destination and derive projectName correctly', async () => {
|
||||||
const expected: NormalizedSchema = {
|
const expected: NormalizedSchema = {
|
||||||
destination: 'my/library',
|
destination: 'my/library',
|
||||||
importPath: '@proj/my/library',
|
importPath: '@proj/my/library',
|
||||||
@ -56,7 +56,7 @@ describe('normalizeSchema', () => {
|
|||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = normalizeSchema(
|
const result = await normalizeSchema(
|
||||||
tree,
|
tree,
|
||||||
{ ...schema, destination: './my/library' },
|
{ ...schema, destination: './my/library' },
|
||||||
projectConfiguration
|
projectConfiguration
|
||||||
@ -65,7 +65,7 @@ describe('normalizeSchema', () => {
|
|||||||
expect(result).toEqual(expected);
|
expect(result).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should use provided import path', () => {
|
it('should use provided import path', async () => {
|
||||||
const expected: NormalizedSchema = {
|
const expected: NormalizedSchema = {
|
||||||
destination: 'my/library',
|
destination: 'my/library',
|
||||||
importPath: '@proj/my-awesome-library',
|
importPath: '@proj/my-awesome-library',
|
||||||
@ -75,7 +75,7 @@ describe('normalizeSchema', () => {
|
|||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = normalizeSchema(
|
const result = await normalizeSchema(
|
||||||
tree,
|
tree,
|
||||||
{ ...schema, importPath: expected.importPath },
|
{ ...schema, importPath: expected.importPath },
|
||||||
projectConfiguration
|
projectConfiguration
|
||||||
@ -90,7 +90,7 @@ describe('normalizeSchema', () => {
|
|||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = normalizeSchema(tree, schema, projectConfiguration);
|
const result = await normalizeSchema(tree, schema, projectConfiguration);
|
||||||
|
|
||||||
expect(result.relativeToRootDestination).toEqual('packages/my/library');
|
expect(result.relativeToRootDestination).toEqual('packages/my/library');
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,32 +1,267 @@
|
|||||||
import { ProjectConfiguration, Tree } from '@nx/devkit';
|
import {
|
||||||
|
ProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
logger,
|
||||||
|
names,
|
||||||
|
readNxJson,
|
||||||
|
stripIndents,
|
||||||
|
updateNxJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
|
import { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
import { prompt } from 'enquirer';
|
||||||
|
import { getImportPath, getNpmScope } from '../../../utilities/get-import-path';
|
||||||
import type { NormalizedSchema, Schema } from '../schema';
|
import type { NormalizedSchema, Schema } from '../schema';
|
||||||
import {
|
import {
|
||||||
getDestination,
|
getDestination,
|
||||||
getNewProjectName,
|
getNewProjectName,
|
||||||
normalizePathSlashes,
|
normalizePathSlashes,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { getImportPath } from '../../../utilities/get-import-path';
|
|
||||||
|
|
||||||
export function normalizeSchema(
|
export async function normalizeSchema(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
schema: Schema,
|
schema: Schema,
|
||||||
projectConfiguration: ProjectConfiguration
|
projectConfiguration: ProjectConfiguration
|
||||||
): NormalizedSchema {
|
): Promise<NormalizedSchema> {
|
||||||
const destination = normalizePathSlashes(schema.destination);
|
const { destination, newProjectName, importPath } =
|
||||||
const newProjectName =
|
await determineProjectNameAndRootOptions(
|
||||||
schema.newProjectName ?? getNewProjectName(destination);
|
|
||||||
|
|
||||||
return {
|
|
||||||
...schema,
|
|
||||||
destination,
|
|
||||||
importPath:
|
|
||||||
schema.importPath ??
|
|
||||||
normalizePathSlashes(getImportPath(tree, destination)),
|
|
||||||
newProjectName,
|
|
||||||
relativeToRootDestination: getDestination(
|
|
||||||
tree,
|
tree,
|
||||||
schema,
|
schema,
|
||||||
projectConfiguration
|
projectConfiguration
|
||||||
),
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...schema,
|
||||||
|
destination: normalizePathSlashes(schema.destination),
|
||||||
|
importPath,
|
||||||
|
newProjectName,
|
||||||
|
relativeToRootDestination: destination,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProjectNameAndRootOptions = {
|
||||||
|
destination: string;
|
||||||
|
newProjectName: string;
|
||||||
|
importPath?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type ProjectNameAndRootFormats = {
|
||||||
|
'as-provided': ProjectNameAndRootOptions;
|
||||||
|
derived?: ProjectNameAndRootOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function determineProjectNameAndRootOptions(
|
||||||
|
tree: Tree,
|
||||||
|
options: Schema,
|
||||||
|
projectConfiguration: ProjectConfiguration
|
||||||
|
): Promise<ProjectNameAndRootOptions> {
|
||||||
|
validateName(
|
||||||
|
options.newProjectName,
|
||||||
|
options.projectNameAndRootFormat,
|
||||||
|
projectConfiguration
|
||||||
|
);
|
||||||
|
const formats = getProjectNameAndRootFormats(
|
||||||
|
tree,
|
||||||
|
options,
|
||||||
|
projectConfiguration
|
||||||
|
);
|
||||||
|
const format =
|
||||||
|
options.projectNameAndRootFormat ??
|
||||||
|
(await determineFormat(tree, formats, options));
|
||||||
|
|
||||||
|
return formats[format];
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateName(
|
||||||
|
name: string | undefined,
|
||||||
|
projectNameAndRootFormat: ProjectNameAndRootFormat | undefined,
|
||||||
|
projectConfiguration: ProjectConfiguration
|
||||||
|
): void {
|
||||||
|
if (!name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectNameAndRootFormat === 'derived' && name.startsWith('@')) {
|
||||||
|
throw new Error(
|
||||||
|
`The new project name "${name}" cannot start with "@" when the "projectNameAndRootFormat" is "derived".`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches two types of project names:
|
||||||
|
*
|
||||||
|
* 1. Valid npm package names (e.g., '@scope/name' or 'name').
|
||||||
|
* 2. Names starting with a letter and can contain any character except whitespace and ':'.
|
||||||
|
*
|
||||||
|
* The second case is to support the legacy behavior (^[a-zA-Z].*$) with the difference
|
||||||
|
* that it doesn't allow the ":" character. It was wrong to allow it because it would
|
||||||
|
* conflict with the notation for tasks.
|
||||||
|
*/
|
||||||
|
const libraryPattern =
|
||||||
|
'(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$';
|
||||||
|
const appPattern = '^[a-zA-Z][^:]*$';
|
||||||
|
|
||||||
|
if (projectConfiguration.projectType === 'application') {
|
||||||
|
const validationRegex = new RegExp(appPattern);
|
||||||
|
if (!validationRegex.test(name)) {
|
||||||
|
throw new Error(
|
||||||
|
`The new project name should match the pattern "${appPattern}". The provided value "${name}" does not match.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (projectConfiguration.projectType === 'library') {
|
||||||
|
const validationRegex = new RegExp(libraryPattern);
|
||||||
|
if (!validationRegex.test(name)) {
|
||||||
|
throw new Error(
|
||||||
|
`The new project name should match the pattern "${libraryPattern}". The provided value "${name}" does not match.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProjectNameAndRootFormats(
|
||||||
|
tree: Tree,
|
||||||
|
schema: Schema,
|
||||||
|
projectConfiguration: ProjectConfiguration
|
||||||
|
): ProjectNameAndRootFormats {
|
||||||
|
let destination = normalizePathSlashes(schema.destination);
|
||||||
|
const normalizedNewProjectName = schema.newProjectName
|
||||||
|
? names(schema.newProjectName).fileName
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const asProvidedProjectName = normalizedNewProjectName ?? schema.projectName;
|
||||||
|
const asProvidedDestination = destination;
|
||||||
|
|
||||||
|
if (normalizedNewProjectName?.startsWith('@')) {
|
||||||
|
return {
|
||||||
|
'as-provided': {
|
||||||
|
destination: asProvidedDestination,
|
||||||
|
importPath:
|
||||||
|
schema.importPath ??
|
||||||
|
// keep the existing import path if the name didn't change
|
||||||
|
(normalizedNewProjectName &&
|
||||||
|
schema.projectName !== normalizedNewProjectName
|
||||||
|
? asProvidedProjectName
|
||||||
|
: undefined),
|
||||||
|
newProjectName: asProvidedProjectName,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let npmScope: string;
|
||||||
|
let asProvidedImportPath = schema.importPath;
|
||||||
|
if (
|
||||||
|
!asProvidedImportPath &&
|
||||||
|
schema.newProjectName &&
|
||||||
|
projectConfiguration.projectType === 'library'
|
||||||
|
) {
|
||||||
|
npmScope = getNpmScope(tree);
|
||||||
|
asProvidedImportPath = npmScope
|
||||||
|
? `${npmScope === '@' ? '' : '@'}${npmScope}/${asProvidedProjectName}`
|
||||||
|
: asProvidedProjectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const derivedProjectName =
|
||||||
|
schema.newProjectName ?? getNewProjectName(destination);
|
||||||
|
const derivedDestination = getDestination(tree, schema, projectConfiguration);
|
||||||
|
|
||||||
|
let derivedImportPath: string;
|
||||||
|
if (projectConfiguration.projectType === 'library') {
|
||||||
|
derivedImportPath =
|
||||||
|
schema.importPath ??
|
||||||
|
normalizePathSlashes(getImportPath(tree, destination));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'as-provided': {
|
||||||
|
destination: asProvidedDestination,
|
||||||
|
newProjectName: asProvidedProjectName,
|
||||||
|
importPath: asProvidedImportPath,
|
||||||
|
},
|
||||||
|
derived: {
|
||||||
|
destination: derivedDestination,
|
||||||
|
newProjectName: derivedProjectName,
|
||||||
|
importPath: derivedImportPath,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function determineFormat(
|
||||||
|
tree: Tree,
|
||||||
|
formats: ProjectNameAndRootFormats,
|
||||||
|
schema: Schema
|
||||||
|
): Promise<ProjectNameAndRootFormat> {
|
||||||
|
if (!formats.derived) {
|
||||||
|
return 'as-provided';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.NX_INTERACTIVE !== 'true' || !isTTY()) {
|
||||||
|
return 'derived';
|
||||||
|
}
|
||||||
|
|
||||||
|
const asProvidedDescription = `As provided:
|
||||||
|
Name: ${formats['as-provided'].newProjectName}
|
||||||
|
Destination: ${formats['as-provided'].destination}`;
|
||||||
|
const asProvidedSelectedValue = `${formats['as-provided'].newProjectName} @ ${formats['as-provided'].destination}`;
|
||||||
|
const derivedDescription = `Derived:
|
||||||
|
Name: ${formats['derived'].newProjectName}
|
||||||
|
Destination: ${formats['derived'].destination}`;
|
||||||
|
const derivedSelectedValue = `${formats['derived'].newProjectName} @ ${formats['derived'].destination}`;
|
||||||
|
|
||||||
|
const result = await prompt<{ format: ProjectNameAndRootFormat }>({
|
||||||
|
type: 'select',
|
||||||
|
name: 'format',
|
||||||
|
message:
|
||||||
|
'What should be the new project name and where should it be moved to?',
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
message: asProvidedDescription,
|
||||||
|
name: asProvidedSelectedValue,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
message: derivedDescription,
|
||||||
|
name: derivedSelectedValue,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
initial: 'as-provided' as any,
|
||||||
|
}).then(({ format }) =>
|
||||||
|
format === asProvidedSelectedValue ? 'as-provided' : 'derived'
|
||||||
|
);
|
||||||
|
|
||||||
|
const callingGenerator =
|
||||||
|
process.env.NX_ANGULAR_MOVE_INVOKED === 'true'
|
||||||
|
? '@nx/angular:move'
|
||||||
|
: '@nx/workspace:move';
|
||||||
|
const deprecationWarning = stripIndents`
|
||||||
|
In Nx 18, the project name and destination will no longer be derived.
|
||||||
|
Please provide the exact new project name and destination in the future.`;
|
||||||
|
|
||||||
|
if (result === 'as-provided') {
|
||||||
|
const { saveDefault } = await prompt<{ saveDefault: boolean }>({
|
||||||
|
type: 'confirm',
|
||||||
|
message: `Would you like to configure Nx to always take the project name and destination as provided for ${callingGenerator}?`,
|
||||||
|
name: 'saveDefault',
|
||||||
|
initial: true,
|
||||||
|
});
|
||||||
|
if (saveDefault) {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
nxJson.generators ??= {};
|
||||||
|
nxJson.generators[callingGenerator] ??= {};
|
||||||
|
nxJson.generators[callingGenerator].projectNameAndRootFormat = result;
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
} else {
|
||||||
|
logger.warn(deprecationWarning);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const example =
|
||||||
|
`Example: nx g ${callingGenerator} --projectName ${schema.projectName} --destination ${formats[result].destination}` +
|
||||||
|
(schema.projectName !== formats[result].newProjectName
|
||||||
|
? ` --newProjectName ${formats[result].newProjectName}`
|
||||||
|
: '');
|
||||||
|
logger.warn(deprecationWarning + '\n' + example);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTTY(): boolean {
|
||||||
|
return !!process.stdout.isTTY && process.env['CI'] !== 'true';
|
||||||
|
}
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
import type { Tree } from '@nx/devkit';
|
||||||
|
import type { Schema } from '../schema';
|
||||||
|
|
||||||
|
type PluginOptions = {
|
||||||
|
oldProjectName: string;
|
||||||
|
newProjectName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function runAngularPlugin(tree: Tree, schema: Schema) {
|
||||||
|
let move: (tree: Tree, schema: PluginOptions) => Promise<void>;
|
||||||
|
try {
|
||||||
|
// nx-ignore-next-line
|
||||||
|
move = require('@nx/angular/src/generators/move/move-impl').move;
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
if (!move) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await move(tree, {
|
||||||
|
oldProjectName: schema.projectName,
|
||||||
|
newProjectName: schema.newProjectName,
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -24,11 +24,14 @@ describe('updateCypressConfig', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,18 +49,18 @@ describe('updateCypressConfig', () => {
|
|||||||
pluginsFile: './src/plugins/index',
|
pluginsFile: './src/plugins/index',
|
||||||
supportFile: false,
|
supportFile: false,
|
||||||
video: true,
|
video: true,
|
||||||
videosFolder: '../../dist/cypress/libs/my-lib/videos',
|
videosFolder: '../../dist/cypress/my-lib/videos',
|
||||||
screenshotsFolder: '../../dist/cypress/libs/my-lib/screenshots',
|
screenshotsFolder: '../../dist/cypress/my-lib/screenshots',
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
};
|
};
|
||||||
writeJson(tree, '/libs/my-destination/cypress.json', cypressJson);
|
writeJson(tree, 'my-destination/cypress.json', cypressJson);
|
||||||
|
|
||||||
updateCypressConfig(tree, schema, projectConfig);
|
updateCypressConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(readJson(tree, '/libs/my-destination/cypress.json')).toEqual({
|
expect(readJson(tree, 'my-destination/cypress.json')).toEqual({
|
||||||
...cypressJson,
|
...cypressJson,
|
||||||
videosFolder: '../../dist/cypress/libs/my-destination/videos',
|
videosFolder: '../../dist/cypress/my-destination/videos',
|
||||||
screenshotsFolder: '../../dist/cypress/libs/my-destination/screenshots',
|
screenshotsFolder: '../../dist/cypress/my-destination/screenshots',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -71,18 +74,16 @@ describe('updateCypressConfig', () => {
|
|||||||
video: false,
|
video: false,
|
||||||
chromeWebSecurity: false,
|
chromeWebSecurity: false,
|
||||||
};
|
};
|
||||||
writeJson(tree, '/libs/my-destination/cypress.json', cypressJson);
|
writeJson(tree, 'my-destination/cypress.json', cypressJson);
|
||||||
|
|
||||||
updateCypressConfig(tree, schema, projectConfig);
|
updateCypressConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(readJson(tree, '/libs/my-destination/cypress.json')).toEqual(
|
expect(readJson(tree, 'my-destination/cypress.json')).toEqual(cypressJson);
|
||||||
cypressJson
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle updating cypress.config.ts', async () => {
|
it('should handle updating cypress.config.ts', async () => {
|
||||||
tree.write(
|
tree.write(
|
||||||
'/libs/my-destination/cypress.config.ts',
|
'my-destination/cypress.config.ts',
|
||||||
`
|
`
|
||||||
import { defineConfig } from 'cypress';
|
import { defineConfig } from 'cypress';
|
||||||
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
||||||
@ -90,23 +91,20 @@ import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
e2e: {
|
e2e: {
|
||||||
nxE2EPreset(__dirname),
|
nxE2EPreset(__dirname),
|
||||||
videosFolder: '../../dist/cypress/libs/my-lib/videos',
|
videosFolder: '../../dist/cypress/my-lib/videos',
|
||||||
screenshotsFolder: '../../dist/cypress/libs/my-lib/screenshots',
|
screenshotsFolder: '../../dist/cypress/my-lib/screenshots',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateCypressConfig(tree, schema, projectConfig);
|
updateCypressConfig(tree, schema, projectConfig);
|
||||||
const fileContent = tree.read(
|
const fileContent = tree.read('my-destination/cypress.config.ts', 'utf-8');
|
||||||
'/libs/my-destination/cypress.config.ts',
|
expect(fileContent).toContain(
|
||||||
'utf-8'
|
`videosFolder: '../../dist/cypress/my-destination/videos'`
|
||||||
);
|
);
|
||||||
expect(fileContent).toContain(
|
expect(fileContent).toContain(
|
||||||
`videosFolder: '../../dist/cypress/libs/my-destination/videos'`
|
`screenshotsFolder: '../../dist/cypress/my-destination/screenshots'`
|
||||||
);
|
|
||||||
expect(fileContent).toContain(
|
|
||||||
`screenshotsFolder: '../../dist/cypress/libs/my-destination/screenshots'`
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,7 +25,7 @@ describe('updateEslint', () => {
|
|||||||
importPath: '@proj/shared-my-destination',
|
importPath: '@proj/shared-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'shared-my-destination',
|
newProjectName: 'shared-my-destination',
|
||||||
relativeToRootDestination: 'libs/shared/my-destination',
|
relativeToRootDestination: 'shared/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
@ -35,6 +35,7 @@ describe('updateEslint', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.None,
|
linter: Linter.None,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
@ -48,33 +49,33 @@ describe('updateEslint', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/.eslintrc.json',
|
'my-lib/.eslintrc.json',
|
||||||
'libs/shared/my-destination/.eslintrc.json'
|
'shared/my-destination/.eslintrc.json'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(readJson(tree, 'shared/my-destination/.eslintrc.json')).toEqual(
|
||||||
readJson(tree, '/libs/shared/my-destination/.eslintrc.json')
|
|
||||||
).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
extends: ['../../../.eslintrc.json'],
|
extends: ['../../.eslintrc.json'],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update .eslintrc.json extends path when project is moved from subdirectory', async () => {
|
it('should update .eslintrc.json extends path when project is moved from subdirectory', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'test',
|
name: 'api-test',
|
||||||
directory: 'api',
|
directory: 'api/test',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename('libs/api/test/.eslintrc.json', 'libs/test/.eslintrc.json');
|
tree.rename('api/test/.eslintrc.json', 'test/.eslintrc.json');
|
||||||
const projectConfig = readProjectConfiguration(tree, 'api-test');
|
const projectConfig = readProjectConfiguration(tree, 'api-test');
|
||||||
|
|
||||||
const newSchema = {
|
const newSchema = {
|
||||||
@ -83,14 +84,14 @@ describe('updateEslint', () => {
|
|||||||
importPath: '@proj/test',
|
importPath: '@proj/test',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'test',
|
newProjectName: 'test',
|
||||||
relativeToRootDestination: 'libs/test',
|
relativeToRootDestination: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateEslintConfig(tree, newSchema, projectConfig);
|
updateEslintConfig(tree, newSchema, projectConfig);
|
||||||
|
|
||||||
expect(readJson(tree, '/libs/test/.eslintrc.json')).toEqual(
|
expect(readJson(tree, 'test/.eslintrc.json')).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
extends: ['../../.eslintrc.json'],
|
extends: ['../.eslintrc.json'],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -99,31 +100,30 @@ describe('updateEslint', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
updateJson(tree, 'libs/my-lib/.eslintrc.json', (eslintRcJson) => {
|
updateJson(tree, 'my-lib/.eslintrc.json', (eslintRcJson) => {
|
||||||
eslintRcJson.extends = [
|
eslintRcJson.extends = [
|
||||||
'plugin:@nx/react',
|
'plugin:@nx/react',
|
||||||
'../../.eslintrc.json',
|
'../.eslintrc.json',
|
||||||
'./customrc.json',
|
'./customrc.json',
|
||||||
];
|
];
|
||||||
return eslintRcJson;
|
return eslintRcJson;
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/.eslintrc.json',
|
'my-lib/.eslintrc.json',
|
||||||
'libs/shared/my-destination/.eslintrc.json'
|
'shared/my-destination/.eslintrc.json'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(readJson(tree, 'shared/my-destination/.eslintrc.json')).toEqual(
|
||||||
readJson(tree, '/libs/shared/my-destination/.eslintrc.json')
|
|
||||||
).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
extends: [
|
extends: [
|
||||||
'plugin:@nx/react',
|
'plugin:@nx/react',
|
||||||
'../../../.eslintrc.json',
|
'../../.eslintrc.json',
|
||||||
'./customrc.json',
|
'./customrc.json',
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
@ -135,24 +135,23 @@ describe('updateEslint', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/.eslintrc.json',
|
'my-lib/.eslintrc.json',
|
||||||
'libs/shared/my-destination/.eslintrc.json'
|
'shared/my-destination/.eslintrc.json'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(readJson(tree, 'shared/my-destination/.eslintrc.json')).toEqual(
|
||||||
readJson(tree, '/libs/shared/my-destination/.eslintrc.json')
|
|
||||||
).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
overrides: expect.arrayContaining([
|
overrides: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
parserOptions: expect.objectContaining({
|
parserOptions: expect.objectContaining({
|
||||||
project: ['libs/shared/my-destination/tsconfig.*?.json'],
|
project: ['shared/my-destination/tsconfig.*?.json'],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
@ -165,36 +164,35 @@ describe('updateEslint', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add another parser project to eslint.json
|
// Add another parser project to eslint.json
|
||||||
const storybookProject = '.storybook/tsconfig.json';
|
const storybookProject = '.storybook/tsconfig.json';
|
||||||
updateJson(tree, '/libs/my-lib/.eslintrc.json', (eslintRcJson) => {
|
updateJson(tree, 'my-lib/.eslintrc.json', (eslintRcJson) => {
|
||||||
eslintRcJson.overrides[0].parserOptions.project.push(
|
eslintRcJson.overrides[0].parserOptions.project.push(
|
||||||
`libs/my-lib/${storybookProject}`
|
`my-lib/${storybookProject}`
|
||||||
);
|
);
|
||||||
return eslintRcJson;
|
return eslintRcJson;
|
||||||
});
|
});
|
||||||
|
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/.eslintrc.json',
|
'my-lib/.eslintrc.json',
|
||||||
'libs/shared/my-destination/.eslintrc.json'
|
'shared/my-destination/.eslintrc.json'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(readJson(tree, 'shared/my-destination/.eslintrc.json')).toEqual(
|
||||||
readJson(tree, '/libs/shared/my-destination/.eslintrc.json')
|
|
||||||
).toEqual(
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
overrides: expect.arrayContaining([
|
overrides: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
parserOptions: expect.objectContaining({
|
parserOptions: expect.objectContaining({
|
||||||
project: [
|
project: [
|
||||||
'libs/shared/my-destination/tsconfig.*?.json',
|
'shared/my-destination/tsconfig.*?.json',
|
||||||
`libs/shared/my-destination/${storybookProject}`,
|
`shared/my-destination/${storybookProject}`,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
@ -208,28 +206,29 @@ describe('updateEslint', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add another parser project to eslint.json
|
// Add another parser project to eslint.json
|
||||||
const storybookProject = '.storybook/tsconfig.json';
|
const storybookProject = '.storybook/tsconfig.json';
|
||||||
updateJson(tree, '/libs/my-lib/.eslintrc.json', (eslintRcJson) => {
|
updateJson(tree, 'my-lib/.eslintrc.json', (eslintRcJson) => {
|
||||||
eslintRcJson.overrides[0].parserOptions.project = `libs/my-lib/${storybookProject}`;
|
eslintRcJson.overrides[0].parserOptions.project = `my-lib/${storybookProject}`;
|
||||||
return eslintRcJson;
|
return eslintRcJson;
|
||||||
});
|
});
|
||||||
|
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/.eslintrc.json',
|
'my-lib/.eslintrc.json',
|
||||||
'libs/shared/my-destination/.eslintrc.json'
|
'shared/my-destination/.eslintrc.json'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
readJson(tree, '/libs/shared/my-destination/.eslintrc.json').overrides[0]
|
readJson(tree, 'shared/my-destination/.eslintrc.json').overrides[0]
|
||||||
.parserOptions
|
.parserOptions
|
||||||
).toEqual({ project: `libs/shared/my-destination/${storybookProject}` });
|
).toEqual({ project: `shared/my-destination/${storybookProject}` });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -244,7 +243,7 @@ describe('updateEslint (flat config)', () => {
|
|||||||
importPath: '@proj/shared-my-destination',
|
importPath: '@proj/shared-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'shared-my-destination',
|
newProjectName: 'shared-my-destination',
|
||||||
relativeToRootDestination: 'libs/shared/my-destination',
|
relativeToRootDestination: 'shared/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
@ -256,6 +255,7 @@ describe('updateEslint (flat config)', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.None,
|
linter: Linter.None,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
@ -269,31 +269,33 @@ describe('updateEslint (flat config)', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
convertToFlat(tree, 'libs/my-lib');
|
convertToFlat(tree, 'my-lib');
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/eslint.config.js',
|
'my-lib/eslint.config.js',
|
||||||
'libs/shared/my-destination/eslint.config.js'
|
'shared/my-destination/eslint.config.js'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
tree.read('libs/shared/my-destination/eslint.config.js', 'utf-8')
|
tree.read('shared/my-destination/eslint.config.js', 'utf-8')
|
||||||
).toEqual(expect.stringContaining(`require('../../../eslint.config.js')`));
|
).toEqual(expect.stringContaining(`require('../../eslint.config.js')`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update config extends path when project is moved from subdirectory', async () => {
|
it('should update config extends path when project is moved from subdirectory', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'test',
|
name: 'api-test',
|
||||||
directory: 'api',
|
directory: 'api/test',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
convertToFlat(tree, 'libs/api/test');
|
convertToFlat(tree, 'api/test');
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename('libs/api/test/eslint.config.js', 'libs/test/eslint.config.js');
|
tree.rename('api/test/eslint.config.js', 'test/eslint.config.js');
|
||||||
|
|
||||||
const projectConfig = readProjectConfiguration(tree, 'api-test');
|
const projectConfig = readProjectConfiguration(tree, 'api-test');
|
||||||
|
|
||||||
@ -303,13 +305,13 @@ describe('updateEslint (flat config)', () => {
|
|||||||
importPath: '@proj/test',
|
importPath: '@proj/test',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'test',
|
newProjectName: 'test',
|
||||||
relativeToRootDestination: 'libs/test',
|
relativeToRootDestination: 'test',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateEslintConfig(tree, newSchema, projectConfig);
|
updateEslintConfig(tree, newSchema, projectConfig);
|
||||||
|
|
||||||
expect(tree.read('libs/test/eslint.config.js', 'utf-8')).toEqual(
|
expect(tree.read('test/eslint.config.js', 'utf-8')).toEqual(
|
||||||
expect.stringContaining(`require('../../eslint.config.js')`)
|
expect.stringContaining(`require('../eslint.config.js')`)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -318,22 +320,23 @@ describe('updateEslint (flat config)', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
convertToFlat(tree, 'libs/my-lib', { hasParser: true });
|
convertToFlat(tree, 'my-lib', { hasParser: true });
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/eslint.config.js',
|
'my-lib/eslint.config.js',
|
||||||
'libs/shared/my-destination/eslint.config.js'
|
'shared/my-destination/eslint.config.js'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
tree.read('libs/shared/my-destination/eslint.config.js', 'utf-8')
|
tree.read('shared/my-destination/eslint.config.js', 'utf-8')
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.stringContaining(
|
expect.stringContaining(
|
||||||
`project: ["libs/shared/my-destination/tsconfig.*?.json"]`
|
`project: ["shared/my-destination/tsconfig.*?.json"]`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -343,27 +346,28 @@ describe('updateEslint (flat config)', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
// Add another parser project to eslint.json
|
// Add another parser project to eslint.json
|
||||||
const storybookProject = '.storybook/tsconfig.json';
|
const storybookProject = '.storybook/tsconfig.json';
|
||||||
convertToFlat(tree, 'libs/my-lib', {
|
convertToFlat(tree, 'my-lib', {
|
||||||
hasParser: true,
|
hasParser: true,
|
||||||
anotherProject: storybookProject,
|
anotherProject: storybookProject,
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/eslint.config.js',
|
'my-lib/eslint.config.js',
|
||||||
'libs/shared/my-destination/eslint.config.js'
|
'shared/my-destination/eslint.config.js'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
tree.read('libs/shared/my-destination/eslint.config.js', 'utf-8')
|
tree.read('shared/my-destination/eslint.config.js', 'utf-8')
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.stringContaining(
|
expect.stringContaining(
|
||||||
`project: ["libs/shared/my-destination/tsconfig.*?.json", "libs/shared/my-destination/${storybookProject}"]`
|
`project: ["shared/my-destination/tsconfig.*?.json", "shared/my-destination/${storybookProject}"]`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -373,23 +377,24 @@ describe('updateEslint (flat config)', () => {
|
|||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
linter: Linter.EsLint,
|
linter: Linter.EsLint,
|
||||||
setParserOptionsProject: true,
|
setParserOptionsProject: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
convertToFlat(tree, 'libs/my-lib', { hasParser: true, isString: true });
|
convertToFlat(tree, 'my-lib', { hasParser: true, isString: true });
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename(
|
||||||
'libs/my-lib/eslint.config.js',
|
'my-lib/eslint.config.js',
|
||||||
'libs/shared/my-destination/eslint.config.js'
|
'shared/my-destination/eslint.config.js'
|
||||||
);
|
);
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
const projectConfig = readProjectConfiguration(tree, 'my-lib');
|
||||||
|
|
||||||
updateEslintConfig(tree, schema, projectConfig);
|
updateEslintConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
tree.read('libs/shared/my-destination/eslint.config.js', 'utf-8')
|
tree.read('shared/my-destination/eslint.config.js', 'utf-8')
|
||||||
).toEqual(
|
).toEqual(
|
||||||
expect.stringContaining(
|
expect.stringContaining(
|
||||||
`project: "libs/shared/my-destination/tsconfig.*?.json"`
|
`project: "shared/my-destination/tsconfig.*?.json"`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -21,8 +21,10 @@ describe('updateImports', () => {
|
|||||||
|
|
||||||
schema = {
|
schema = {
|
||||||
projectName: 'my-source',
|
projectName: 'my-source',
|
||||||
|
newProjectName: 'my-destination',
|
||||||
destination: 'my-destination',
|
destination: 'my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,14 +35,17 @@ describe('updateImports', () => {
|
|||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-destination',
|
name: 'my-destination',
|
||||||
config: 'project',
|
config: 'project',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`
|
`
|
||||||
@ -53,7 +58,7 @@ describe('updateImports', () => {
|
|||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -66,12 +71,19 @@ describe('updateImports', () => {
|
|||||||
* be updated.
|
* be updated.
|
||||||
*/
|
*/
|
||||||
it('should not update import paths when they contain a partial match', async () => {
|
it('should not update import paths when they contain a partial match', async () => {
|
||||||
await libraryGenerator(tree, { name: 'table' });
|
await libraryGenerator(tree, {
|
||||||
await libraryGenerator(tree, { name: 'tab' });
|
name: 'table',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'tab',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`
|
`
|
||||||
@ -92,7 +104,7 @@ describe('updateImports', () => {
|
|||||||
importPath: '@proj/tabs',
|
importPath: '@proj/tabs',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'tabs',
|
newProjectName: 'tabs',
|
||||||
relativeToRootDestination: 'libs/tabs',
|
relativeToRootDestination: 'tabs',
|
||||||
},
|
},
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
@ -107,12 +119,19 @@ describe('updateImports', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should correctly update deep imports', async () => {
|
it('should correctly update deep imports', async () => {
|
||||||
await libraryGenerator(tree, { name: 'table' });
|
await libraryGenerator(tree, {
|
||||||
await libraryGenerator(tree, { name: 'tab' });
|
name: 'table',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'tab',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`
|
`
|
||||||
@ -133,7 +152,7 @@ describe('updateImports', () => {
|
|||||||
importPath: '@proj/tabs',
|
importPath: '@proj/tabs',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'tabs',
|
newProjectName: 'tabs',
|
||||||
relativeToRootDestination: 'libs/tabs',
|
relativeToRootDestination: 'tabs',
|
||||||
},
|
},
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
@ -148,12 +167,19 @@ describe('updateImports', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update dynamic imports', async () => {
|
it('should update dynamic imports', async () => {
|
||||||
await libraryGenerator(tree, { name: 'table' });
|
await libraryGenerator(tree, {
|
||||||
await libraryGenerator(tree, { name: 'tab' });
|
name: 'table',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'tab',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`
|
`
|
||||||
@ -173,7 +199,7 @@ describe('updateImports', () => {
|
|||||||
importPath: '@proj/tabs',
|
importPath: '@proj/tabs',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'tabs',
|
newProjectName: 'tabs',
|
||||||
relativeToRootDestination: 'libs/tabs',
|
relativeToRootDestination: 'tabs',
|
||||||
},
|
},
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
@ -194,12 +220,19 @@ describe('updateImports', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update require imports', async () => {
|
it('should update require imports', async () => {
|
||||||
await libraryGenerator(tree, { name: 'table' });
|
await libraryGenerator(tree, {
|
||||||
await libraryGenerator(tree, { name: 'tab' });
|
name: 'table',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'tab',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`
|
`
|
||||||
@ -219,7 +252,7 @@ describe('updateImports', () => {
|
|||||||
importPath: '@proj/tabs',
|
importPath: '@proj/tabs',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'tabs',
|
newProjectName: 'tabs',
|
||||||
relativeToRootDestination: 'libs/tabs',
|
relativeToRootDestination: 'tabs',
|
||||||
},
|
},
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
@ -244,14 +277,17 @@ describe('updateImports', () => {
|
|||||||
// source and destination to make sure that the workspace has libraries with those names.
|
// source and destination to make sure that the workspace has libraries with those names.
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-destination',
|
name: 'my-destination',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-importer',
|
name: 'my-importer',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const importerFilePath = 'libs/my-importer/src/importer.ts';
|
const importerFilePath = 'my-importer/src/importer.ts';
|
||||||
tree.write(
|
tree.write(
|
||||||
importerFilePath,
|
importerFilePath,
|
||||||
`import { MyClass } from '@proj/my-source';
|
`import { MyClass } from '@proj/my-source';
|
||||||
@ -263,7 +299,7 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(
|
await normalizeSchema(
|
||||||
tree,
|
tree,
|
||||||
{
|
{
|
||||||
...schema,
|
...schema,
|
||||||
@ -282,31 +318,33 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
it('should update project ref in the root tsconfig.base.json', async () => {
|
it('should update project ref in the root tsconfig.base.json', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
||||||
expect(tsConfig.compilerOptions.paths).toEqual({
|
expect(tsConfig.compilerOptions.paths).toEqual({
|
||||||
'@proj/my-destination': ['libs/my-destination/src/index.ts'],
|
'@proj/my-destination': ['my-destination/src/index.ts'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update project ref in the root tsconfig.base.json for secondary entry points', async () => {
|
it('should update project ref in the root tsconfig.base.json for secondary entry points', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
updateJson(tree, '/tsconfig.base.json', (json) => {
|
updateJson(tree, '/tsconfig.base.json', (json) => {
|
||||||
json.compilerOptions.paths['@proj/my-source/testing'] = [
|
json.compilerOptions.paths['@proj/my-source/testing'] = [
|
||||||
'libs/my-source/testing/src/index.ts',
|
'my-source/testing/src/index.ts',
|
||||||
];
|
];
|
||||||
json.compilerOptions.paths['@proj/different-alias'] = [
|
json.compilerOptions.paths['@proj/different-alias'] = [
|
||||||
'libs/my-source/some-path/src/index.ts',
|
'my-source/some-path/src/index.ts',
|
||||||
];
|
];
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
@ -314,17 +352,15 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
||||||
expect(tsConfig.compilerOptions.paths).toEqual({
|
expect(tsConfig.compilerOptions.paths).toEqual({
|
||||||
'@proj/my-destination': ['libs/my-destination/src/index.ts'],
|
'@proj/my-destination': ['my-destination/src/index.ts'],
|
||||||
'@proj/my-destination/testing': [
|
'@proj/my-destination/testing': ['my-destination/testing/src/index.ts'],
|
||||||
'libs/my-destination/testing/src/index.ts',
|
'@proj/different-alias': ['my-destination/some-path/src/index.ts'],
|
||||||
],
|
|
||||||
'@proj/different-alias': ['libs/my-destination/some-path/src/index.ts'],
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -332,12 +368,13 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
tree.delete('libs');
|
tree.delete('libs');
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -351,18 +388,19 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
tree.rename('tsconfig.base.json', 'tsconfig.json');
|
tree.rename('tsconfig.base.json', 'tsconfig.json');
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfig = readJson(tree, '/tsconfig.json');
|
const tsConfig = readJson(tree, '/tsconfig.json');
|
||||||
expect(tsConfig.compilerOptions.paths).toEqual({
|
expect(tsConfig.compilerOptions.paths).toEqual({
|
||||||
'@proj/my-destination': ['libs/my-destination/src/index.ts'],
|
'@proj/my-destination': ['my-destination/src/index.ts'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -374,30 +412,32 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
);
|
);
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(tree, schema, projectConfig),
|
await normalizeSchema(tree, schema, projectConfig),
|
||||||
projectConfig
|
projectConfig
|
||||||
);
|
);
|
||||||
|
|
||||||
const tsConfig = readJson(tree, '/tsconfig.json');
|
const tsConfig = readJson(tree, '/tsconfig.json');
|
||||||
expect(tsConfig.compilerOptions.paths).toEqual({
|
expect(tsConfig.compilerOptions.paths).toEqual({
|
||||||
'@proj/my-destination': ['libs/my-destination/src/index.ts'],
|
'@proj/my-destination': ['my-destination/src/index.ts'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should only update the project ref paths in the tsconfig file when --updateImportPath=false', async () => {
|
it('should only update the project ref paths in the tsconfig file when --updateImportPath=false', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
|
||||||
updateImports(
|
updateImports(
|
||||||
tree,
|
tree,
|
||||||
normalizeSchema(
|
await normalizeSchema(
|
||||||
tree,
|
tree,
|
||||||
{
|
{
|
||||||
...schema,
|
...schema,
|
||||||
@ -411,7 +451,7 @@ export MyExtendedClass extends MyClass {};`
|
|||||||
|
|
||||||
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
const tsConfig = readJson(tree, '/tsconfig.base.json');
|
||||||
expect(tsConfig.compilerOptions.paths).toEqual({
|
expect(tsConfig.compilerOptions.paths).toEqual({
|
||||||
'@proj/my-source': ['libs/my-destination/src/index.ts'],
|
'@proj/my-source': ['my-destination/src/index.ts'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -35,7 +35,6 @@ export function updateImports(
|
|||||||
project: ProjectConfiguration
|
project: ProjectConfiguration
|
||||||
) {
|
) {
|
||||||
if (project.projectType === 'application') {
|
if (project.projectType === 'application') {
|
||||||
// These shouldn't be imported anywhere?
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +87,8 @@ export function updateImports(
|
|||||||
// if the import path doesn't start with the main entry point import path,
|
// 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'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
|
// it as-is, but we'll update the path it points to
|
||||||
to: p.startsWith(mainEntryPointImportPath)
|
to:
|
||||||
|
schema.importPath && p.startsWith(mainEntryPointImportPath)
|
||||||
? p.replace(mainEntryPointImportPath, schema.importPath)
|
? p.replace(mainEntryPointImportPath, schema.importPath)
|
||||||
: null,
|
: null,
|
||||||
})),
|
})),
|
||||||
|
|||||||
@ -16,6 +16,7 @@ describe('updateJestConfig', () => {
|
|||||||
it('should handle jest config not existing', async () => {
|
it('should handle jest config not existing', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
const schema: NormalizedSchema = {
|
const schema: NormalizedSchema = {
|
||||||
@ -24,7 +25,7 @@ describe('updateJestConfig', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(() => updateJestConfig(tree, schema, projectConfig)).not.toThrow();
|
expect(() => updateJestConfig(tree, schema, projectConfig)).not.toThrow();
|
||||||
@ -34,16 +35,17 @@ describe('updateJestConfig', () => {
|
|||||||
const jestConfig = `module.exports = {
|
const jestConfig = `module.exports = {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
preset: '../../jest.config.ts',
|
preset: '../../jest.config.ts',
|
||||||
coverageDirectory: '../../coverage/libs/my-source',
|
coverageDirectory: '../coverage/my-source',
|
||||||
snapshotSerializers: [
|
snapshotSerializers: [
|
||||||
'jest-preset-angular/AngularSnapshotSerializer.js',
|
'jest-preset-angular/AngularSnapshotSerializer.js',
|
||||||
'jest-preset-angular/HTMLCommentSerializer.js'
|
'jest-preset-angular/HTMLCommentSerializer.js'
|
||||||
]
|
]
|
||||||
};`;
|
};`;
|
||||||
const jestConfigPath = '/libs/my-destination/jest.config.ts';
|
const jestConfigPath = 'my-destination/jest.config.ts';
|
||||||
const rootJestConfigPath = '/jest.config.ts';
|
const rootJestConfigPath = '/jest.config.ts';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(jestConfigPath, jestConfig);
|
tree.write(jestConfigPath, jestConfig);
|
||||||
@ -53,7 +55,7 @@ describe('updateJestConfig', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateJestConfig(tree, schema, projectConfig);
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
@ -62,25 +64,62 @@ describe('updateJestConfig', () => {
|
|||||||
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
||||||
expect(jestConfigAfter).toContain(`name: 'my-destination'`);
|
expect(jestConfigAfter).toContain(`name: 'my-destination'`);
|
||||||
expect(jestConfigAfter).toContain(
|
expect(jestConfigAfter).toContain(
|
||||||
`coverageDirectory: '../../coverage/libs/my-destination'`
|
`coverageDirectory: '../coverage/my-destination'`
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update jest configs properly even if project is in many layers of subfolders', async () => {
|
it('should update the name and dir correctly when moving to a nested dir', async () => {
|
||||||
const jestConfig = `module.exports = {
|
const jestConfig = `module.exports = {
|
||||||
name: 'some-test-dir-my-source',
|
name: 'my-source',
|
||||||
preset: '../../jest.config.ts',
|
preset: '../../jest.config.ts',
|
||||||
coverageDirectory: '../../coverage/libs/some/test/dir/my-source',
|
coverageDirectory: '../coverage/my-source',
|
||||||
snapshotSerializers: [
|
snapshotSerializers: [
|
||||||
'jest-preset-angular/AngularSnapshotSerializer.js',
|
'jest-preset-angular/AngularSnapshotSerializer.js',
|
||||||
'jest-preset-angular/HTMLCommentSerializer.js'
|
'jest-preset-angular/HTMLCommentSerializer.js'
|
||||||
]
|
]
|
||||||
};`;
|
};`;
|
||||||
const jestConfigPath = '/libs/other/test/dir/my-destination/jest.config.ts';
|
const jestConfigPath = 'my-source/data-access/jest.config.ts';
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
|
tree.write(jestConfigPath, jestConfig);
|
||||||
|
const schema: NormalizedSchema = {
|
||||||
|
projectName: 'my-source',
|
||||||
|
destination: 'my-source/data-access',
|
||||||
|
importPath: '@proj/my-soource-data-access',
|
||||||
|
updateImportPath: true,
|
||||||
|
newProjectName: 'my-source-data-access',
|
||||||
|
relativeToRootDestination: 'my-source/data-access',
|
||||||
|
};
|
||||||
|
|
||||||
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
|
const jestConfigAfter = tree.read(jestConfigPath, 'utf-8');
|
||||||
|
expect(jestConfigAfter).toContain(`name: 'my-source-data-access'`);
|
||||||
|
expect(jestConfigAfter).toContain(
|
||||||
|
`coverageDirectory: '../coverage/my-source/data-access'`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update jest configs properly even if project is in many layers of subfolders', async () => {
|
||||||
|
const jestConfig = `module.exports = {
|
||||||
|
name: 'some-test-dir-my-source',
|
||||||
|
preset: '../jest.config.ts',
|
||||||
|
coverageDirectory: '../coverage/some/test/dir/my-source',
|
||||||
|
snapshotSerializers: [
|
||||||
|
'jest-preset-angular/AngularSnapshotSerializer.js',
|
||||||
|
'jest-preset-angular/HTMLCommentSerializer.js'
|
||||||
|
]
|
||||||
|
};`;
|
||||||
|
const jestConfigPath = 'other/test/dir/my-destination/jest.config.ts';
|
||||||
const rootJestConfigPath = '/jest.config.ts';
|
const rootJestConfigPath = '/jest.config.ts';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'some/test/dir/my-source',
|
name: 'some-test-dir-my-source',
|
||||||
|
directory: 'some/test/dir/my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(
|
const projectConfig = readProjectConfiguration(
|
||||||
tree,
|
tree,
|
||||||
@ -93,7 +132,7 @@ describe('updateJestConfig', () => {
|
|||||||
importPath: '@proj/other-test-dir-my-destination',
|
importPath: '@proj/other-test-dir-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'other-test-dir-my-destination',
|
newProjectName: 'other-test-dir-my-destination',
|
||||||
relativeToRootDestination: 'libs/other/test/dir/my-destination',
|
relativeToRootDestination: 'other/test/dir/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateJestConfig(tree, schema, projectConfig);
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
@ -101,7 +140,7 @@ describe('updateJestConfig', () => {
|
|||||||
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
||||||
expect(jestConfigAfter).toContain(`name: 'other-test-dir-my-destination'`);
|
expect(jestConfigAfter).toContain(`name: 'other-test-dir-my-destination'`);
|
||||||
expect(jestConfigAfter).toContain(
|
expect(jestConfigAfter).toContain(
|
||||||
`coverageDirectory: '../../coverage/libs/other/test/dir/my-destination'`
|
`coverageDirectory: '../coverage/other/test/dir/my-destination'`
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||||
});
|
});
|
||||||
@ -109,12 +148,14 @@ describe('updateJestConfig', () => {
|
|||||||
it('updates the root config if not using `getJestProjects()`', async () => {
|
it('updates the root config if not using `getJestProjects()`', async () => {
|
||||||
const rootJestConfigPath = '/jest.config.ts';
|
const rootJestConfigPath = '/jest.config.ts';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'some/test/dir/my-source',
|
name: 'some-test-dir-my-source',
|
||||||
|
directory: 'some/test/dir/my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
tree.write(
|
tree.write(
|
||||||
rootJestConfigPath,
|
rootJestConfigPath,
|
||||||
`module.exports = {
|
`module.exports = {
|
||||||
projects: ['<rootDir>/libs/some/test/dir/my-source']
|
projects: ['<rootDir>/some/test/dir/my-source']
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
@ -128,31 +169,33 @@ describe('updateJestConfig', () => {
|
|||||||
importPath: '@proj/other-test-dir-my-destination',
|
importPath: '@proj/other-test-dir-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'other-test-dir-my-destination',
|
newProjectName: 'other-test-dir-my-destination',
|
||||||
relativeToRootDestination: 'libs/other/test/dir/my-destination',
|
relativeToRootDestination: 'other/test/dir/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateJestConfig(tree, schema, projectConfig);
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
||||||
expect(rootJestConfigAfter).not.toContain(
|
expect(rootJestConfigAfter).not.toContain(
|
||||||
'<rootDir>/libs/some/test/dir/my-source'
|
'<rootDir>/some/test/dir/my-source'
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).toContain(
|
expect(rootJestConfigAfter).toContain(
|
||||||
'<rootDir>/libs/other/test/dir/my-destination'
|
'<rootDir>/other/test/dir/my-destination'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('updates the root config if `getJestProjects()` is used but old path exists', async () => {
|
it('updates the root config if `getJestProjects()` is used but old path exists', async () => {
|
||||||
const rootJestConfigPath = '/jest.config.ts';
|
const rootJestConfigPath = '/jest.config.ts';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'some/test/dir/my-source',
|
name: 'some-test-dir-my-source',
|
||||||
|
directory: 'some/test/dir/my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
tree.write(
|
tree.write(
|
||||||
rootJestConfigPath,
|
rootJestConfigPath,
|
||||||
`const { getJestProjects } = require('@nx/jest');
|
`const { getJestProjects } = require('@nx/jest');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
projects: [...getJestProjects(), '<rootDir>/libs/some/test/dir/my-source']
|
projects: [...getJestProjects(), '<rootDir>/some/test/dir/my-source']
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
@ -166,17 +209,17 @@ module.exports = {
|
|||||||
importPath: '@proj/other-test-dir-my-destination',
|
importPath: '@proj/other-test-dir-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'other-test-dir-my-destination',
|
newProjectName: 'other-test-dir-my-destination',
|
||||||
relativeToRootDestination: 'libs/other/test/dir/my-destination',
|
relativeToRootDestination: 'other/test/dir/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateJestConfig(tree, schema, projectConfig);
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
||||||
expect(rootJestConfigAfter).not.toContain(
|
expect(rootJestConfigAfter).not.toContain(
|
||||||
'<rootDir>/libs/some/test/dir/my-source'
|
'<rootDir>/some/test/dir/my-source'
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).not.toContain(
|
expect(rootJestConfigAfter).not.toContain(
|
||||||
'<rootDir>/libs/other/test/dir/my-destination'
|
'<rootDir>/other/test/dir/my-destination'
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||||
});
|
});
|
||||||
@ -184,14 +227,16 @@ module.exports = {
|
|||||||
it('updates the root config if `getJestProjects()` is used with other projects in the array', async () => {
|
it('updates the root config if `getJestProjects()` is used with other projects in the array', async () => {
|
||||||
const rootJestConfigPath = '/jest.config.ts';
|
const rootJestConfigPath = '/jest.config.ts';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'some/test/dir/my-source',
|
name: 'some-test-dir-my-source',
|
||||||
|
directory: 'some/test/dir/my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
tree.write(
|
tree.write(
|
||||||
rootJestConfigPath,
|
rootJestConfigPath,
|
||||||
`const { getJestProjects } = require('@nx/jest');
|
`const { getJestProjects } = require('@nx/jest');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
projects: [...getJestProjects(), '<rootDir>/libs/some/test/dir/my-source', '<rootDir>/libs/foo']
|
projects: [...getJestProjects(), '<rootDir>/some/test/dir/my-source', '<rootDir>/foo']
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
@ -205,19 +250,19 @@ module.exports = {
|
|||||||
importPath: '@proj/other-test-dir-my-destination',
|
importPath: '@proj/other-test-dir-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'other-test-dir-my-destination',
|
newProjectName: 'other-test-dir-my-destination',
|
||||||
relativeToRootDestination: 'libs/other/test/dir/my-destination',
|
relativeToRootDestination: 'other/test/dir/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateJestConfig(tree, schema, projectConfig);
|
updateJestConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
const rootJestConfigAfter = tree.read(rootJestConfigPath, 'utf-8');
|
||||||
expect(rootJestConfigAfter).not.toContain(
|
expect(rootJestConfigAfter).not.toContain(
|
||||||
'<rootDir>/libs/some/test/dir/my-source'
|
'<rootDir>/some/test/dir/my-source'
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).not.toContain(
|
expect(rootJestConfigAfter).not.toContain(
|
||||||
'<rootDir>/libs/other/test/dir/my-destination'
|
'<rootDir>/other/test/dir/my-destination'
|
||||||
);
|
);
|
||||||
expect(rootJestConfigAfter).toContain('<rootDir>/libs/foo');
|
expect(rootJestConfigAfter).toContain('<rootDir>/foo');
|
||||||
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
expect(rootJestConfigAfter).toContain('getJestProjects()');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -22,16 +22,38 @@ export function updateJestConfig(
|
|||||||
if (tree.exists(jestConfigPath)) {
|
if (tree.exists(jestConfigPath)) {
|
||||||
const oldContent = tree.read(jestConfigPath, 'utf-8');
|
const oldContent = tree.read(jestConfigPath, 'utf-8');
|
||||||
|
|
||||||
|
let newContent = oldContent;
|
||||||
|
if (schema.projectName !== schema.newProjectName) {
|
||||||
// ensure both single and double quotes are replaced
|
// ensure both single and double quotes are replaced
|
||||||
const findName = new RegExp(
|
const findName = new RegExp(
|
||||||
`'${schema.projectName}'|"${schema.projectName}"|\`${schema.projectName}\``,
|
`'${schema.projectName}'|"${schema.projectName}"|\`${schema.projectName}\``,
|
||||||
'g'
|
'g'
|
||||||
);
|
);
|
||||||
const findDir = new RegExp(project.root, 'g');
|
newContent = oldContent.replace(findName, `'${schema.newProjectName}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dirRegex = new RegExp(`\\/${project.root}\\/`, 'g');
|
||||||
|
if (dirRegex.test(newContent)) {
|
||||||
|
newContent = newContent.replace(
|
||||||
|
dirRegex,
|
||||||
|
`/${schema.relativeToRootDestination}/`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dirRegex = new RegExp(`\\/${project.root}['"\`]`, 'g');
|
||||||
|
if (dirRegex.test(newContent)) {
|
||||||
|
newContent = newContent.replace(
|
||||||
|
dirRegex,
|
||||||
|
`/${schema.relativeToRootDestination}'`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
dirRegex = new RegExp(`['"\`]${project.root}\\/`, 'g');
|
||||||
|
if (dirRegex.test(newContent)) {
|
||||||
|
newContent = newContent.replace(
|
||||||
|
dirRegex,
|
||||||
|
`'${schema.relativeToRootDestination}/`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const newContent = oldContent
|
|
||||||
.replace(findName, `'${schema.newProjectName}'`)
|
|
||||||
.replace(findDir, schema.relativeToRootDestination);
|
|
||||||
tree.write(jestConfigPath, newContent);
|
tree.write(jestConfigPath, newContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,11 +17,14 @@ describe('updatePackageJson', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle package.json not existing', async () => {
|
it('should handle package.json not existing', async () => {
|
||||||
@ -34,11 +37,11 @@ describe('updatePackageJson', () => {
|
|||||||
const packageJson = {
|
const packageJson = {
|
||||||
name: '@proj/my-lib',
|
name: '@proj/my-lib',
|
||||||
};
|
};
|
||||||
writeJson(tree, '/libs/my-destination/package.json', packageJson);
|
writeJson(tree, 'my-destination/package.json', packageJson);
|
||||||
|
|
||||||
updatePackageJson(tree, schema);
|
updatePackageJson(tree, schema);
|
||||||
|
|
||||||
expect(readJson(tree, '/libs/my-destination/package.json')).toEqual({
|
expect(readJson(tree, 'my-destination/package.json')).toEqual({
|
||||||
...packageJson,
|
...packageJson,
|
||||||
name: '@proj/my-destination',
|
name: '@proj/my-destination',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,6 +12,10 @@ interface PartialPackageJson {
|
|||||||
* @param schema The options provided to the schematic
|
* @param schema The options provided to the schematic
|
||||||
*/
|
*/
|
||||||
export function updatePackageJson(tree: Tree, schema: NormalizedSchema) {
|
export function updatePackageJson(tree: Tree, schema: NormalizedSchema) {
|
||||||
|
if (!schema.importPath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const packageJsonPath = path.join(
|
const packageJsonPath = path.join(
|
||||||
schema.relativeToRootDestination,
|
schema.relativeToRootDestination,
|
||||||
'package.json'
|
'package.json'
|
||||||
|
|||||||
@ -16,16 +16,17 @@ describe('updateProjectRootFiles', () => {
|
|||||||
it('should update the relative root in files at the root of the project', async () => {
|
it('should update the relative root in files at the root of the project', async () => {
|
||||||
const testFile = `module.exports = {
|
const testFile = `module.exports = {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
preset: '../../jest.config.js',
|
preset: '../jest.config.js',
|
||||||
coverageDirectory: '../../coverage/libs/my-source',
|
coverageDirectory: '../coverage/my-source',
|
||||||
snapshotSerializers: [
|
snapshotSerializers: [
|
||||||
'jest-preset-angular/AngularSnapshotSerializer.js',
|
'jest-preset-angular/AngularSnapshotSerializer.js',
|
||||||
'jest-preset-angular/HTMLCommentSerializer.js'
|
'jest-preset-angular/HTMLCommentSerializer.js'
|
||||||
]
|
]
|
||||||
};`;
|
};`;
|
||||||
const testFilePath = '/libs/subfolder/my-destination/jest.config.js';
|
const testFilePath = 'subfolder/my-destination/jest.config.js';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(testFilePath, testFile);
|
tree.write(testFilePath, testFile);
|
||||||
@ -35,15 +36,15 @@ describe('updateProjectRootFiles', () => {
|
|||||||
importPath: '@proj/subfolder-my-destination',
|
importPath: '@proj/subfolder-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'subfolder-my-destination',
|
newProjectName: 'subfolder-my-destination',
|
||||||
relativeToRootDestination: 'libs/subfolder/my-destination',
|
relativeToRootDestination: 'subfolder/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateProjectRootFiles(tree, schema, projectConfig);
|
updateProjectRootFiles(tree, schema, projectConfig);
|
||||||
|
|
||||||
const testFileAfter = tree.read(testFilePath, 'utf-8');
|
const testFileAfter = tree.read(testFilePath, 'utf-8');
|
||||||
expect(testFileAfter).toContain(`preset: '../../../jest.config.js'`);
|
expect(testFileAfter).toContain(`preset: '../../jest.config.js'`);
|
||||||
expect(testFileAfter).toContain(
|
expect(testFileAfter).toContain(
|
||||||
`coverageDirectory: '../../../coverage/libs/my-source'`
|
`coverageDirectory: '../../coverage/my-source'`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -18,7 +18,7 @@ describe('updateReadme', () => {
|
|||||||
importPath: '@proj/shared-my-destination',
|
importPath: '@proj/shared-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'shared-my-destination',
|
newProjectName: 'shared-my-destination',
|
||||||
relativeToRootDestination: 'libs/shared/my-destination',
|
relativeToRootDestination: 'shared/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||||
@ -27,6 +27,7 @@ describe('updateReadme', () => {
|
|||||||
it('should handle README.md not existing', async () => {
|
it('should handle README.md not existing', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const readmePath = join(schema.relativeToRootDestination, 'README.md');
|
const readmePath = join(schema.relativeToRootDestination, 'README.md');
|
||||||
tree.delete(readmePath);
|
tree.delete(readmePath);
|
||||||
@ -39,17 +40,15 @@ describe('updateReadme', () => {
|
|||||||
it('should update README.md contents', async () => {
|
it('should update README.md contents', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
// This step is usually handled elsewhere
|
// This step is usually handled elsewhere
|
||||||
tree.rename(
|
tree.rename('my-lib/README.md', 'shared/my-destination/README.md');
|
||||||
'libs/my-lib/README.md',
|
|
||||||
'libs/shared/my-destination/README.md'
|
|
||||||
);
|
|
||||||
|
|
||||||
updateReadme(tree, schema);
|
updateReadme(tree, schema);
|
||||||
|
|
||||||
const content = tree
|
const content = tree
|
||||||
.read('/libs/shared/my-destination/README.md')
|
.read('shared/my-destination/README.md')
|
||||||
.toString('utf8');
|
.toString('utf8');
|
||||||
expect(content).toMatch('# shared-my-destination');
|
expect(content).toMatch('# shared-my-destination');
|
||||||
expect(content).toMatch('nx test shared-my-destination');
|
expect(content).toMatch('nx test shared-my-destination');
|
||||||
|
|||||||
@ -16,6 +16,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
it('should handle storybook config not existing', async () => {
|
it('should handle storybook config not existing', async () => {
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
const schema: NormalizedSchema = {
|
const schema: NormalizedSchema = {
|
||||||
@ -24,7 +25,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
importPath: '@proj/my-destination',
|
importPath: '@proj/my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'my-destination',
|
newProjectName: 'my-destination',
|
||||||
relativeToRootDestination: 'libs/my-destination',
|
relativeToRootDestination: 'my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
@ -34,14 +35,14 @@ describe('updateStorybookConfig', () => {
|
|||||||
|
|
||||||
it('should update the import path for main.js', async () => {
|
it('should update the import path for main.js', async () => {
|
||||||
const storybookMain = `
|
const storybookMain = `
|
||||||
const rootMain = require('../../../.storybook/main');
|
const rootMain = require('../../.storybook/main');
|
||||||
module.exports = rootMain;
|
module.exports = rootMain;
|
||||||
`;
|
`;
|
||||||
const storybookMainPath =
|
const storybookMainPath = 'namespace/my-destination/.storybook/main.js';
|
||||||
'/libs/namespace/my-destination/.storybook/main.js';
|
|
||||||
|
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(storybookMainPath, storybookMain);
|
tree.write(storybookMainPath, storybookMain);
|
||||||
@ -51,25 +52,26 @@ describe('updateStorybookConfig', () => {
|
|||||||
importPath: '@proj/namespace-my-destination',
|
importPath: '@proj/namespace-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'namespace-my-destination',
|
newProjectName: 'namespace-my-destination',
|
||||||
relativeToRootDestination: 'libs/namespace/my-destination',
|
relativeToRootDestination: 'namespace/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStorybookConfig(tree, schema, projectConfig);
|
updateStorybookConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
const storybookMainAfter = tree.read(storybookMainPath, 'utf-8');
|
const storybookMainAfter = tree.read(storybookMainPath, 'utf-8');
|
||||||
expect(storybookMainAfter).toContain(
|
expect(storybookMainAfter).toContain(
|
||||||
`const rootMain = require('../../../../.storybook/main');`
|
`const rootMain = require('../../../.storybook/main');`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the import path for webpack.config.json', async () => {
|
it('should update the import path for webpack.config.json', async () => {
|
||||||
const storybookWebpackConfig = `
|
const storybookWebpackConfig = `
|
||||||
const rootWebpackConfig = require('../../../.storybook/webpack.config');
|
const rootWebpackConfig = require('../../.storybook/webpack.config');
|
||||||
`;
|
`;
|
||||||
const storybookWebpackConfigPath =
|
const storybookWebpackConfigPath =
|
||||||
'/libs/namespace/my-destination/.storybook/webpack.config.js';
|
'namespace/my-destination/.storybook/webpack.config.js';
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(storybookWebpackConfigPath, storybookWebpackConfig);
|
tree.write(storybookWebpackConfigPath, storybookWebpackConfig);
|
||||||
@ -79,7 +81,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
importPath: '@proj/namespace-my-destination',
|
importPath: '@proj/namespace-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'namespace-my-destination',
|
newProjectName: 'namespace-my-destination',
|
||||||
relativeToRootDestination: 'libs/namespace/my-destination',
|
relativeToRootDestination: 'namespace/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStorybookConfig(tree, schema, projectConfig);
|
updateStorybookConfig(tree, schema, projectConfig);
|
||||||
@ -89,28 +91,28 @@ describe('updateStorybookConfig', () => {
|
|||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(storybookWebpackConfigAfter).toContain(
|
expect(storybookWebpackConfigAfter).toContain(
|
||||||
`const rootWebpackConfig = require('../../../../.storybook/webpack.config');`
|
`const rootWebpackConfig = require('../../../.storybook/webpack.config');`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('directory', () => {
|
describe('directory', () => {
|
||||||
it('should update the import path for directory/main.js', async () => {
|
it('should update the import path for directory/main.js', async () => {
|
||||||
const storybookMain = `
|
const storybookMain = `
|
||||||
|
const rootMain = require('../../.storybook/main');
|
||||||
|
module.exports = rootMain;
|
||||||
|
`;
|
||||||
|
const storybookMainPath = 'namespace/my-destination/.storybook/main.js';
|
||||||
|
|
||||||
|
const storybookNestedMain = `
|
||||||
const rootMain = require('../../../.storybook/main');
|
const rootMain = require('../../../.storybook/main');
|
||||||
module.exports = rootMain;
|
module.exports = rootMain;
|
||||||
`;
|
|
||||||
const storybookMainPath =
|
|
||||||
'/libs/namespace/my-destination/.storybook/main.js';
|
|
||||||
|
|
||||||
const storybookNestedMain = `
|
|
||||||
const rootMain = require('../../../../.storybook/main');
|
|
||||||
module.exports = rootMain;
|
|
||||||
`;
|
`;
|
||||||
const storybookNestedMainPath =
|
const storybookNestedMainPath =
|
||||||
'/libs/namespace/my-destination/.storybook/nested/main.js';
|
'namespace/my-destination/.storybook/nested/main.js';
|
||||||
|
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(storybookMainPath, storybookMain);
|
tree.write(storybookMainPath, storybookMain);
|
||||||
@ -121,39 +123,40 @@ describe('updateStorybookConfig', () => {
|
|||||||
importPath: '@proj/namespace-my-destination',
|
importPath: '@proj/namespace-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'namespace-my-destination',
|
newProjectName: 'namespace-my-destination',
|
||||||
relativeToRootDestination: 'libs/namespace/my-destination',
|
relativeToRootDestination: 'namespace/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStorybookConfig(tree, schema, projectConfig);
|
updateStorybookConfig(tree, schema, projectConfig);
|
||||||
|
|
||||||
const storybookMainAfter = tree.read(storybookMainPath, 'utf-8');
|
const storybookMainAfter = tree.read(storybookMainPath, 'utf-8');
|
||||||
expect(storybookMainAfter).toContain(
|
expect(storybookMainAfter).toContain(
|
||||||
`const rootMain = require('../../../../.storybook/main');`
|
`const rootMain = require('../../../.storybook/main');`
|
||||||
);
|
);
|
||||||
const storybookNestedMainAfter = tree.read(
|
const storybookNestedMainAfter = tree.read(
|
||||||
storybookNestedMainPath,
|
storybookNestedMainPath,
|
||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(storybookNestedMainAfter).toContain(
|
expect(storybookNestedMainAfter).toContain(
|
||||||
`const rootMain = require('../../../../../.storybook/main');`
|
`const rootMain = require('../../../../.storybook/main');`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update the import path for directory/webpack.config.json', async () => {
|
it('should update the import path for directory/webpack.config.json', async () => {
|
||||||
const storybookWebpackConfig = `
|
const storybookWebpackConfig = `
|
||||||
const rootWebpackConfig = require('../../../.storybook/webpack.config');
|
const rootWebpackConfig = require('../../.storybook/webpack.config');
|
||||||
`;
|
`;
|
||||||
const storybookWebpackConfigPath =
|
const storybookWebpackConfigPath =
|
||||||
'/libs/namespace/my-destination/.storybook/webpack.config.js';
|
'namespace/my-destination/.storybook/webpack.config.js';
|
||||||
|
|
||||||
const storybookNestedWebpackConfig = `
|
const storybookNestedWebpackConfig = `
|
||||||
const rootWebpackConfig = require('../../../../.storybook/webpack.config');
|
const rootWebpackConfig = require('../../../.storybook/webpack.config');
|
||||||
`;
|
`;
|
||||||
const storybookNestedWebpackConfigPath =
|
const storybookNestedWebpackConfigPath =
|
||||||
'/libs/namespace/my-destination/.storybook/nested/webpack.config.js';
|
'namespace/my-destination/.storybook/nested/webpack.config.js';
|
||||||
|
|
||||||
await libraryGenerator(tree, {
|
await libraryGenerator(tree, {
|
||||||
name: 'my-source',
|
name: 'my-source',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
const projectConfig = readProjectConfiguration(tree, 'my-source');
|
||||||
tree.write(storybookWebpackConfigPath, storybookWebpackConfig);
|
tree.write(storybookWebpackConfigPath, storybookWebpackConfig);
|
||||||
@ -167,7 +170,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
importPath: '@proj/namespace-my-destination',
|
importPath: '@proj/namespace-my-destination',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
newProjectName: 'namespace-my-destination',
|
newProjectName: 'namespace-my-destination',
|
||||||
relativeToRootDestination: 'libs/namespace/my-destination',
|
relativeToRootDestination: 'namespace/my-destination',
|
||||||
};
|
};
|
||||||
|
|
||||||
updateStorybookConfig(tree, schema, projectConfig);
|
updateStorybookConfig(tree, schema, projectConfig);
|
||||||
@ -177,7 +180,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(storybookWebpackConfigAfter).toContain(
|
expect(storybookWebpackConfigAfter).toContain(
|
||||||
`const rootWebpackConfig = require('../../../../.storybook/webpack.config');`
|
`const rootWebpackConfig = require('../../../.storybook/webpack.config');`
|
||||||
);
|
);
|
||||||
|
|
||||||
const storybookNestedWebpackConfigAfter = tree.read(
|
const storybookNestedWebpackConfigAfter = tree.read(
|
||||||
@ -185,7 +188,7 @@ describe('updateStorybookConfig', () => {
|
|||||||
'utf-8'
|
'utf-8'
|
||||||
);
|
);
|
||||||
expect(storybookNestedWebpackConfigAfter).toContain(
|
expect(storybookNestedWebpackConfigAfter).toContain(
|
||||||
`const rootWebpackConfig = require('../../../../../.storybook/webpack.config');`
|
`const rootWebpackConfig = require('../../../../.storybook/webpack.config');`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -19,10 +19,6 @@ export function getDestination(
|
|||||||
schema: Schema,
|
schema: Schema,
|
||||||
project: ProjectConfiguration
|
project: ProjectConfiguration
|
||||||
): string {
|
): string {
|
||||||
if (schema.destinationRelativeToRoot) {
|
|
||||||
return schema.destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
const projectType = project.projectType;
|
const projectType = project.projectType;
|
||||||
|
|
||||||
const workspaceLayout = getWorkspaceLayout(host);
|
const workspaceLayout = getWorkspaceLayout(host);
|
||||||
|
|||||||
@ -12,47 +12,61 @@ describe('move', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update jest config when moving down directories', async () => {
|
it('should update jest config when moving down directories', async () => {
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
await moveGenerator(tree, {
|
await moveGenerator(tree, {
|
||||||
projectName: 'my-lib',
|
projectName: 'my-lib',
|
||||||
importPath: '@proj/shared-mylib',
|
importPath: '@proj/shared-mylib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
destination: 'shared/my-lib-new',
|
destination: 'shared/my-lib-new',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const jestConfigPath = 'libs/shared/my-lib-new/jest.config.ts';
|
|
||||||
|
const jestConfigPath = 'shared/my-lib-new/jest.config.ts';
|
||||||
const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
|
const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
|
||||||
expect(tree.exists(jestConfigPath)).toBeTruthy();
|
expect(tree.exists(jestConfigPath)).toBeTruthy();
|
||||||
expect(afterJestConfig).toContain("preset: '../../../jest.preset.js'");
|
expect(afterJestConfig).toContain("preset: '../../jest.preset.js'");
|
||||||
expect(afterJestConfig).toContain(
|
expect(afterJestConfig).toContain(
|
||||||
"coverageDirectory: '../../../coverage/libs/shared/my-lib-new'"
|
"coverageDirectory: '../../coverage/shared/my-lib-new'"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update jest config when moving up directories', async () => {
|
it('should update jest config when moving up directories', async () => {
|
||||||
await libraryGenerator(tree, { name: 'shared/my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'shared-my-lib',
|
||||||
|
directory: 'shared/my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
await moveGenerator(tree, {
|
await moveGenerator(tree, {
|
||||||
projectName: 'shared-my-lib',
|
projectName: 'shared-my-lib',
|
||||||
importPath: '@proj/mylib',
|
importPath: '@proj/mylib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
destination: 'my-lib-new',
|
destination: 'my-lib-new',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
const jestConfigPath = 'libs/my-lib-new/jest.config.ts';
|
|
||||||
|
const jestConfigPath = 'my-lib-new/jest.config.ts';
|
||||||
const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
|
const afterJestConfig = tree.read(jestConfigPath, 'utf-8');
|
||||||
expect(tree.exists(jestConfigPath)).toBeTruthy();
|
expect(tree.exists(jestConfigPath)).toBeTruthy();
|
||||||
expect(afterJestConfig).toContain("preset: '../../jest.preset.js'");
|
expect(afterJestConfig).toContain("preset: '../jest.preset.js'");
|
||||||
expect(afterJestConfig).toContain(
|
expect(afterJestConfig).toContain(
|
||||||
"coverageDirectory: '../../coverage/libs/my-lib-new'"
|
"coverageDirectory: '../coverage/my-lib-new'"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update $schema path when move', async () => {
|
it('should update $schema path when move', async () => {
|
||||||
await libraryGenerator(tree, { name: 'my-lib' });
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
});
|
||||||
|
|
||||||
let projectJson = readJson(tree, 'libs/my-lib/project.json');
|
let projectJson = readJson(tree, 'my-lib/project.json');
|
||||||
expect(projectJson['$schema']).toEqual(
|
expect(projectJson['$schema']).toEqual(
|
||||||
'../../node_modules/nx/schemas/project-schema.json'
|
'../node_modules/nx/schemas/project-schema.json'
|
||||||
);
|
);
|
||||||
|
|
||||||
await moveGenerator(tree, {
|
await moveGenerator(tree, {
|
||||||
@ -60,11 +74,12 @@ describe('move', () => {
|
|||||||
importPath: '@proj/shared-mylib',
|
importPath: '@proj/shared-mylib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
destination: 'shared/my-lib-new',
|
destination: 'shared/my-lib-new',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
projectJson = readJson(tree, 'libs/shared/my-lib-new/project.json');
|
projectJson = readJson(tree, 'shared/my-lib-new/project.json');
|
||||||
expect(projectJson['$schema']).toEqual(
|
expect(projectJson['$schema']).toEqual(
|
||||||
'../../../node_modules/nx/schemas/project-schema.json'
|
'../../node_modules/nx/schemas/project-schema.json'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -80,6 +95,7 @@ describe('move', () => {
|
|||||||
buildable: true,
|
buildable: true,
|
||||||
unitTestRunner: 'jest',
|
unitTestRunner: 'jest',
|
||||||
linter: 'eslint',
|
linter: 'eslint',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
updateJson(tree, 'tsconfig.json', (json) => {
|
updateJson(tree, 'tsconfig.json', (json) => {
|
||||||
@ -100,12 +116,13 @@ describe('move', () => {
|
|||||||
importPath: '@proj/my-lib',
|
importPath: '@proj/my-lib',
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
destination: 'my-lib',
|
destination: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(readJson(tree, 'libs/my-lib/project.json')).toMatchObject({
|
expect(readJson(tree, 'my-lib/project.json')).toMatchObject({
|
||||||
name: 'my-lib',
|
name: 'my-lib',
|
||||||
$schema: '../../node_modules/nx/schemas/project-schema.json',
|
$schema: '../node_modules/nx/schemas/project-schema.json',
|
||||||
sourceRoot: 'libs/my-lib/src',
|
sourceRoot: 'my-lib/src',
|
||||||
projectType: 'library',
|
projectType: 'library',
|
||||||
targets: {
|
targets: {
|
||||||
build: {
|
build: {
|
||||||
@ -113,18 +130,15 @@ describe('move', () => {
|
|||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
outputPath: 'dist/my-lib',
|
outputPath: 'dist/my-lib',
|
||||||
main: 'libs/my-lib/src/index.ts',
|
main: 'my-lib/src/index.ts',
|
||||||
tsConfig: 'libs/my-lib/tsconfig.lib.json',
|
tsConfig: 'my-lib/tsconfig.lib.json',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
lint: {
|
lint: {
|
||||||
executor: '@nx/linter:eslint',
|
executor: '@nx/linter:eslint',
|
||||||
outputs: ['{options.outputFile}'],
|
outputs: ['{options.outputFile}'],
|
||||||
options: {
|
options: {
|
||||||
lintFilePatterns: [
|
lintFilePatterns: ['my-lib/**/*.ts', 'my-lib/package.json'],
|
||||||
'libs/my-lib/**/*.ts',
|
|
||||||
'libs/my-lib/package.json',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
@ -134,22 +148,22 @@ describe('move', () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(readJson(tree, 'libs/my-lib/tsconfig.json')).toMatchObject({
|
expect(readJson(tree, 'my-lib/tsconfig.json')).toMatchObject({
|
||||||
extends: '../../tsconfig.base.json',
|
extends: '../tsconfig.base.json',
|
||||||
files: ['../../node_modules/@foo/bar/index.d.ts'],
|
files: ['../node_modules/@foo/bar/index.d.ts'],
|
||||||
references: [
|
references: [
|
||||||
{ path: './tsconfig.lib.json' },
|
{ path: './tsconfig.lib.json' },
|
||||||
{ path: './tsconfig.spec.json' },
|
{ path: './tsconfig.spec.json' },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const jestConfig = tree.read('libs/my-lib/jest.config.lib.ts', 'utf-8');
|
const jestConfig = tree.read('my-lib/jest.config.lib.ts', 'utf-8');
|
||||||
expect(jestConfig).toContain(`preset: '../../jest.preset.js'`);
|
expect(jestConfig).toContain(`preset: '../jest.preset.js'`);
|
||||||
|
|
||||||
expect(tree.exists('libs/my-lib/tsconfig.lib.json')).toBeTruthy();
|
expect(tree.exists('my-lib/tsconfig.lib.json')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/tsconfig.spec.json')).toBeTruthy();
|
expect(tree.exists('my-lib/tsconfig.spec.json')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/.eslintrc.json')).toBeTruthy();
|
expect(tree.exists('my-lib/.eslintrc.json')).toBeTruthy();
|
||||||
expect(tree.exists('libs/my-lib/src/index.ts')).toBeTruthy();
|
expect(tree.exists('my-lib/src/index.ts')).toBeTruthy();
|
||||||
|
|
||||||
// Test that other libs and workspace files are not moved.
|
// Test that other libs and workspace files are not moved.
|
||||||
expect(tree.exists('package.json')).toBeTruthy();
|
expect(tree.exists('package.json')).toBeTruthy();
|
||||||
@ -162,4 +176,32 @@ describe('move', () => {
|
|||||||
expect(tree.exists('jest.config.ts')).toBeTruthy();
|
expect(tree.exists('jest.config.ts')).toBeTruthy();
|
||||||
expect(tree.exists('.eslintrc.base.json')).toBeTruthy();
|
expect(tree.exists('.eslintrc.base.json')).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should move project correctly when --project-name-and-root-format=derived', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
name: 'my-lib',
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
});
|
||||||
|
|
||||||
|
await moveGenerator(tree, {
|
||||||
|
projectName: 'my-lib',
|
||||||
|
importPath: '@proj/shared-mylib',
|
||||||
|
updateImportPath: true,
|
||||||
|
destination: 'shared/my-lib-new',
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
});
|
||||||
|
|
||||||
|
const projectJson = readJson(tree, 'libs/shared/my-lib-new/project.json');
|
||||||
|
expect(projectJson['$schema']).toEqual(
|
||||||
|
'../../../node_modules/nx/schemas/project-schema.json'
|
||||||
|
);
|
||||||
|
const afterJestConfig = tree.read(
|
||||||
|
'libs/shared/my-lib-new/jest.config.ts',
|
||||||
|
'utf-8'
|
||||||
|
);
|
||||||
|
expect(afterJestConfig).toContain("preset: '../../../jest.preset.js'");
|
||||||
|
expect(afterJestConfig).toContain(
|
||||||
|
"coverageDirectory: '../../../coverage/libs/shared/my-lib-new'"
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { checkDestination } from './lib/check-destination';
|
|||||||
import { createProjectConfigurationInNewDestination } from './lib/create-project-configuration-in-new-destination';
|
import { createProjectConfigurationInNewDestination } from './lib/create-project-configuration-in-new-destination';
|
||||||
import { moveProjectFiles } from './lib/move-project-files';
|
import { moveProjectFiles } from './lib/move-project-files';
|
||||||
import { normalizeSchema } from './lib/normalize-schema';
|
import { normalizeSchema } from './lib/normalize-schema';
|
||||||
|
import { runAngularPlugin } from './lib/run-angular-plugin';
|
||||||
import { updateBuildTargets } from './lib/update-build-targets';
|
import { updateBuildTargets } from './lib/update-build-targets';
|
||||||
import { updateCypressConfig } from './lib/update-cypress-config';
|
import { updateCypressConfig } from './lib/update-cypress-config';
|
||||||
import { updateDefaultProject } from './lib/update-default-project';
|
import { updateDefaultProject } from './lib/update-default-project';
|
||||||
@ -28,9 +29,16 @@ import {
|
|||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export async function moveGenerator(tree: Tree, rawSchema: Schema) {
|
export async function moveGenerator(tree: Tree, rawSchema: Schema) {
|
||||||
|
await moveGeneratorInternal(tree, {
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
...rawSchema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function moveGeneratorInternal(tree: Tree, rawSchema: Schema) {
|
||||||
let projectConfig = readProjectConfiguration(tree, rawSchema.projectName);
|
let projectConfig = readProjectConfiguration(tree, rawSchema.projectName);
|
||||||
checkDestination(tree, rawSchema, projectConfig);
|
const schema = await normalizeSchema(tree, rawSchema, projectConfig);
|
||||||
const schema = normalizeSchema(tree, rawSchema, projectConfig);
|
checkDestination(tree, schema, rawSchema.destination);
|
||||||
|
|
||||||
if (projectConfig.root === '.') {
|
if (projectConfig.root === '.') {
|
||||||
maybeExtractTsConfigBase(tree);
|
maybeExtractTsConfigBase(tree);
|
||||||
@ -55,6 +63,8 @@ export async function moveGenerator(tree: Tree, rawSchema: Schema) {
|
|||||||
updateDefaultProject(tree, schema);
|
updateDefaultProject(tree, schema);
|
||||||
updateImplicitDependencies(tree, schema);
|
updateImplicitDependencies(tree, schema);
|
||||||
|
|
||||||
|
await runAngularPlugin(tree, schema);
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
|
import { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
destination: string;
|
destination: string;
|
||||||
importPath?: string;
|
importPath?: string;
|
||||||
updateImportPath: boolean;
|
updateImportPath: boolean;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
destinationRelativeToRoot?: boolean;
|
|
||||||
newProjectName?: string;
|
newProjectName?: string;
|
||||||
|
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
importPath: string;
|
|
||||||
relativeToRootDestination: string;
|
relativeToRootDestination: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,13 @@
|
|||||||
"description": "The name of the project to move.",
|
"description": "The name of the project to move.",
|
||||||
"x-dropdown": "projects"
|
"x-dropdown": "projects"
|
||||||
},
|
},
|
||||||
|
"newProjectName": {
|
||||||
|
"type": "string",
|
||||||
|
"alias": "project",
|
||||||
|
"description": "The new name of the project after the move.",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"destination": {
|
"destination": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The folder to move the project into.",
|
"description": "The folder to move the project into.",
|
||||||
@ -26,6 +33,11 @@
|
|||||||
"index": 0
|
"index": 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"projectNameAndRootFormat": {
|
||||||
|
"description": "Whether to generate the new project name and destination as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["as-provided", "derived"]
|
||||||
|
},
|
||||||
"importPath": {
|
"importPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The new import path to use in the `tsconfig.base.json`."
|
"description": "The new import path to use in the `tsconfig.base.json`."
|
||||||
|
|||||||
@ -60,7 +60,7 @@ async function moveWorkspaceGeneratorsToLocalPlugin(tree: Tree) {
|
|||||||
);
|
);
|
||||||
project = readProjectConfiguration(tree, PROJECT_NAME);
|
project = readProjectConfiguration(tree, PROJECT_NAME);
|
||||||
}
|
}
|
||||||
await updateExistingPlugin(tree, project);
|
updateExistingPlugin(tree, project);
|
||||||
return tasks;
|
return tasks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +187,7 @@ async function createNewPlugin(tree: Tree) {
|
|||||||
e2eTestRunner: 'none',
|
e2eTestRunner: 'none',
|
||||||
publishable: false,
|
publishable: false,
|
||||||
});
|
});
|
||||||
getCreateGeneratorsJson()(
|
await getCreateGeneratorsJson()(
|
||||||
tree,
|
tree,
|
||||||
readProjectConfiguration(tree, PROJECT_NAME).root,
|
readProjectConfiguration(tree, PROJECT_NAME).root,
|
||||||
PROJECT_NAME
|
PROJECT_NAME
|
||||||
@ -207,8 +207,8 @@ function moveGeneratedPlugin(
|
|||||||
projectName: PROJECT_NAME,
|
projectName: PROJECT_NAME,
|
||||||
newProjectName: PROJECT_NAME,
|
newProjectName: PROJECT_NAME,
|
||||||
updateImportPath: true,
|
updateImportPath: true,
|
||||||
destinationRelativeToRoot: true,
|
|
||||||
importPath: importPath,
|
importPath: importPath,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export function getImportPath(tree: Tree, projectDirectory: string): string {
|
|||||||
: projectDirectory;
|
: projectDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNpmScope(tree: Tree) {
|
export function getNpmScope(tree: Tree) {
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
|
|
||||||
// TODO(v17): Remove reading this from nx.json
|
// TODO(v17): Remove reading this from nx.json
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user