Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(repo): remove projectNameAndRoot nx.json option #19218

Merged
merged 1 commit into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions docs/generated/devkit/NxJsonConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,7 @@ Where new apps + libs should be placed

#### Type declaration

| Name | Type |
| :-------------------------- | :----------------------------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |
| Name | Type |
| :--------- | :------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |
9 changes: 4 additions & 5 deletions docs/generated/devkit/Workspace.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,11 +280,10 @@ Where new apps + libs should be placed

#### Type declaration

| Name | Type |
| :-------------------------- | :----------------------------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |
| Name | Type |
| :--------- | :------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |

#### Inherited from

Expand Down
4 changes: 3 additions & 1 deletion e2e/linter/src/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,9 @@ describe('Linter', () => {
bundler: 'vite',
e2eTestRunner: 'none',
});
runCLI(`generate @nx/js:lib ${mylib} --directory libs/${mylib}`);
runCLI(
`generate @nx/js:lib ${mylib} --directory libs/${mylib} --projectNameAndRootFormat as-provided`
);

// migrate to flat structure
runCLI(`generate @nx/linter:convert-to-flat-config`);
Expand Down
4 changes: 0 additions & 4 deletions e2e/utils/create-project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,6 @@ export function newProject({
console.warn(
'ATTENTION: The workspace generated for this e2e test does not use the new as-provided project name/root format. Please update this test'
);
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
delete nxJson.workspaceLayout;
return nxJson;
});
createFile('apps/.gitkeep');
createFile('libs/.gitkeep');
}
Expand Down
44 changes: 29 additions & 15 deletions e2e/workspace-create-npm/src/create-nx-workspace-npm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/angular:app ${appName} --no-interactive`);
runCLI(
`generate @nx/angular:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
}, 1_000_000);
Expand All @@ -64,7 +66,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/angular:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/angular:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -81,7 +83,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() =>
runCLI(
`generate @nx/js:library ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/js:library ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
)
).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -97,7 +99,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() =>
runCLI(`generate @nx/web:app ${appName} --no-interactive`)
runCLI(
`generate @nx/web:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
)
).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand All @@ -108,7 +112,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/react:app ${appName} --no-interactive`);
runCLI(
`generate @nx/react:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand All @@ -120,7 +126,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/react:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/react:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -136,7 +142,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/next:app ${appName} --no-interactive`);
runCLI(
`generate @nx/next:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand All @@ -148,7 +156,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/next:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/next:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -166,7 +174,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/react-native:app ${appName} --install=false --no-interactive`
`generate @nx/react-native:app ${appName} --install=false --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -179,7 +187,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/react-native:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/react-native:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -195,7 +203,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/node:app ${appName} --no-interactive`);
runCLI(
`generate @nx/node:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand All @@ -207,7 +217,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/node:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/node:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -223,7 +233,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/nest:app ${appName} --no-interactive`);
runCLI(
`generate @nx/nest:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand All @@ -235,7 +247,7 @@ describe('create-nx-workspace --preset=npm', () => {

expect(() => {
runCLI(
`generate @nx/nest:lib ${libName} --directory packages/${libName} --no-interactive`
`generate @nx/nest:lib ${libName} --directory packages/${libName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
Expand All @@ -251,7 +263,9 @@ describe('create-nx-workspace --preset=npm', () => {
const appName = uniq('my-app');

expect(() => {
runCLI(`generate @nx/express:app ${appName} --no-interactive`);
runCLI(
`generate @nx/express:app ${appName} --projectNameAndRootFormat as-provided --no-interactive`
);
}).not.toThrowError();
checkFilesExist('tsconfig.base.json');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as enquirer from 'enquirer';
import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace';
import type { Tree } from 'nx/src/generators/tree';
import { updateJson } from 'nx/src/generators/utils/json';
import { readNxJson } from 'nx/src/generators/utils/nx-json';
import { determineProjectNameAndRootOptions } from './project-name-and-root-utils';

describe('determineProjectNameAndRootOptions', () => {
Expand Down Expand Up @@ -330,43 +329,6 @@ describe('determineProjectNameAndRootOptions', () => {
restoreOriginalInteractiveMode();
});

it('should prompt to save default when as-provided is choosen', async () => {
// simulate interactive mode
ensureInteractiveMode();
const promptSpy = jest
.spyOn(enquirer, 'prompt')
.mockImplementation(() =>
Promise.resolve({ format: 'lib-name @ shared', saveDefault: true })
);

await determineProjectNameAndRootOptions(tree, {
name: 'libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '@nx/some-plugin:app',
});

expect(promptSpy).toHaveBeenCalledTimes(2);

expect(readNxJson(tree).workspaceLayout).toEqual({
projectNameAndRootFormat: 'as-provided',
});

promptSpy.mockReset();

await determineProjectNameAndRootOptions(tree, {
name: 'libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '@nx/some-plugin:app',
});

expect(promptSpy).not.toHaveBeenCalled();

// restore original interactive mode
restoreOriginalInteractiveMode();
});

it('should directly use format as-provided and not prompt when the name is a scoped package name', async () => {
// simulate interactive mode
ensureInteractiveMode();
Expand Down
35 changes: 1 addition & 34 deletions packages/devkit/src/generators/project-name-and-root-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,9 @@ export async function determineProjectNameAndRootOptions(
> {
validateName(options.name, options.projectNameAndRootFormat);
const formats = getProjectNameAndRootFormats(tree, options);
const configuredDefault = getDefaultProjectNameAndRootFormat(tree);

if (configuredDefault === 'derived') {
logger.warn(
deprecationWarning + '\n' + getExample(options.callingGenerator, formats)
);
}

const format =
options.projectNameAndRootFormat ??
configuredDefault ??
(await determineFormat(tree, formats, options.callingGenerator));

return {
Expand Down Expand Up @@ -179,38 +171,13 @@ async function determineFormat(
format === asProvidedSelectedValue ? 'as-provided' : 'derived'
);

if (result === 'as-provided' && callingGenerator) {
const { saveDefault } = await prompt<{ saveDefault: boolean }>({
type: 'confirm',
message: `Would you like to configure Nx to always take project name and root as provided for ${callingGenerator}?`,
name: 'saveDefault',
initial: true,
});
if (saveDefault) {
setProjectNameAndRootFormatDefault(tree);
} else {
logger.warn(deprecationWarning);
}
} else {
if (result === 'derived' && callingGenerator) {
const example = getExample(callingGenerator, formats);
logger.warn(deprecationWarning + '\n' + example);
}

return result;
}

function setProjectNameAndRootFormatDefault(tree: Tree) {
const nxJson = readNxJson(tree);
nxJson.workspaceLayout ??= {};
nxJson.workspaceLayout.projectNameAndRootFormat = 'as-provided';
updateNxJson(tree, nxJson);
}

function getDefaultProjectNameAndRootFormat(tree: Tree) {
const nxJson = readNxJson(tree);
return nxJson.workspaceLayout?.projectNameAndRootFormat;
}

function getProjectNameAndRootFormats(
tree: Tree,
options: ProjectGenerationOptions
Expand Down
1 change: 0 additions & 1 deletion packages/nx/src/config/nx-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
workspaceLayout?: {
libsDir?: string;
appsDir?: string;
projectNameAndRootFormat?: 'as-provided' | 'derived';
};
/**
* Available Task Runners
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { readJson, writeJson } from '../../generators/utils/json';
import { createTree } from '../../generators/testing-utils/create-tree';
import removeProjectNameAndRootFormat from './remove-project-name-and-root-format';
import { NxJsonConfiguration } from '../../config/nx-json';

describe('removeProjectNameAndRootFormat', () => {
let tree;
beforeEach(() => {
tree = createTree();
});

it('should not error if nx.json is not present', async () => {
await removeProjectNameAndRootFormat(tree);
});

it('should not update nx.json if projectNameAndRoot is not present', async () => {
const nxJson: NxJsonConfiguration = {};
writeJson(tree, 'nx.json', nxJson);
await removeProjectNameAndRootFormat(tree);
expect(readJson(tree, 'nx.json')).toEqual(nxJson);
});

it('should remove projectNameAndRoot if it is present', async () => {
const nxJson: any = {
workspaceLayout: {
libsDir: 'libs',
projectNameAndRootFormat: 'as-provided',
},
};
writeJson(tree, 'nx.json', nxJson);
await removeProjectNameAndRootFormat(tree);
expect(readJson(tree, 'nx.json').workspaceLayout).toEqual({
libsDir: 'libs',
});
});

it('should remove workspaceLayout if it is present', async () => {
const nxJson: any = {
workspaceLayout: {
projectNameAndRootFormat: 'as-provided',
},
};
writeJson(tree, 'nx.json', nxJson);
await removeProjectNameAndRootFormat(tree);
expect(readJson(tree, 'nx.json').workspaceLayout).not.toBeDefined();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Tree } from '../../generators/tree';
import { updateJson } from '../../generators/utils/json';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';

export default async function removeProjectNameAndRootFormat(tree: Tree) {
if (!tree.exists('nx.json')) {
return;
}

updateJson(tree, 'nx.json', (nxJson) => {
if (!nxJson.workspaceLayout) {
return nxJson;
}

delete nxJson.workspaceLayout.projectNameAndRootFormat;

if (Object.keys(nxJson.workspaceLayout).length === 0) {
delete nxJson.workspaceLayout;
}

return nxJson;
});

await formatChangedFilesWithPrettierIfAvailable(tree);
}
Loading