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(misc): introduce a way to set the project name/root format for all generators #18971

Merged
merged 1 commit into from
Sep 1, 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: 5 additions & 4 deletions docs/generated/devkit/NxJsonConfiguration.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ Where new apps + libs should be placed

#### Type declaration

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

#### Type declaration

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

#### Inherited from

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

// migrate to flat structure
runCLI(`generate @nx/linter:convert-to-flat-config`);
Expand Down
10 changes: 9 additions & 1 deletion e2e/utils/create-project-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
RunCmdOpts,
runCommand,
} from './command-utils';
import { output } from '@nx/devkit';
import { NxJsonConfiguration, output } from '@nx/devkit';
import { readFileSync } from 'fs';
import { join } from 'path';

Expand All @@ -41,6 +41,7 @@ let projName: string;
export function newProject({
name = uniq('proj'),
packageManager = getSelectedPackageManager(),
unsetProjectNameAndRootFormat = true,
} = {}): string {
try {
const projScope = 'proj';
Expand All @@ -51,6 +52,13 @@ export function newProject({
packageManager,
});

if (unsetProjectNameAndRootFormat) {
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
delete nxJson.workspaceLayout;
return nxJson;
});
}

// Temporary hack to prevent installing with `--frozen-lockfile`
if (isCI && packageManager === 'pnpm') {
updateFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,10 +348,21 @@ describe('determineProjectNameAndRootOptions', () => {

expect(promptSpy).toHaveBeenCalledTimes(2);

expect(readNxJson(tree).generators['@nx/some-plugin:app']).toEqual({
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();
});
Expand Down
22 changes: 16 additions & 6 deletions packages/devkit/src/generators/project-name-and-root-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ export async function determineProjectNameAndRootOptions(
const formats = getProjectNameAndRootFormats(tree, options);
const format =
options.projectNameAndRootFormat ??
(await determineFormat(tree, formats, options.callingGenerator));
(getDefaultProjectNameAndRootFormat(tree) === 'as-provided'
? 'as-provided'
: await determineFormat(tree, formats, options.callingGenerator));

return {
...formats[format],
Expand Down Expand Up @@ -167,11 +169,7 @@ async function determineFormat(
initial: true,
});
if (saveDefault) {
const nxJson = readNxJson(tree);
nxJson.generators ??= {};
nxJson.generators[callingGenerator] ??= {};
nxJson.generators[callingGenerator].projectNameAndRootFormat = result;
updateNxJson(tree, nxJson);
setProjectNameAndRootFormatDefault(tree);
} else {
logger.warn(deprecationWarning);
}
Expand All @@ -183,6 +181,18 @@ async function determineFormat(
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 ?? 'derived';
}

function getProjectNameAndRootFormats(
tree: Tree,
options: ProjectGenerationOptions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export function toNodeApplicationGeneratorOptions(
name: options.name,
directory: options.directory,
frontendProject: options.frontendProject,
projectNameAndRootFormat: options.projectNameAndRootFormat,
linter: options.linter,
skipFormat: true,
skipPackageJson: options.skipPackageJson,
Expand Down
5 changes: 5 additions & 0 deletions packages/nx/schemas/nx-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@
"appsDir": {
"type": "string",
"description": "Default folder name for apps."
},
"projectNameAndRootFormat": {
"type": "string",
"description": "Default method of handling arguments for generating projects",
"enum": ["as-provided", "derived"]
}
},
"additionalProperties": false
Expand Down
5 changes: 3 additions & 2 deletions packages/nx/src/config/nx-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
* Where new apps + libs should be placed
*/
workspaceLayout?: {
libsDir: string;
appsDir: string;
libsDir?: string;
appsDir?: string;
projectNameAndRootFormat?: 'as-provided' | 'derived';
};
/**
* Available Task Runners
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,8 @@ exports[`new should generate an empty nx.json 1`] = `
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`);
const validateNxJson = ajv.compile(nxSchema);
Expand Down Expand Up @@ -174,6 +177,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ function createNxJson(
},
},
},
workspaceLayout: {
projectNameAndRootFormat: 'as-provided',
},
};

nxJson.targetDefaults = {
Expand Down
17 changes: 9 additions & 8 deletions packages/workspace/src/generators/new/new.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,28 @@ export interface NormalizedSchema extends Schema {
isCustomPreset: boolean;
}

export async function newGenerator(host: Tree, opts: Schema) {
export async function newGenerator(tree: Tree, opts: Schema) {
const options = normalizeOptions(opts);
validateOptions(options, host);
validateOptions(options, tree);

await generateWorkspaceFiles(host, { ...options, nxCloud: undefined } as any);
await generateWorkspaceFiles(tree, { ...options, nxCloud: undefined } as any);

addPresetDependencies(host, options);
addCloudDependencies(host, options);
addPresetDependencies(tree, options);

addCloudDependencies(tree, options);

return async () => {
const pmc = getPackageManagerCommand(options.packageManager);
if (pmc.preInstall) {
execSync(pmc.preInstall, {
cwd: joinPathFragments(host.root, options.directory),
cwd: joinPathFragments(tree.root, options.directory),
stdio: process.env.NX_GENERATE_QUIET === 'true' ? 'ignore' : 'inherit',
});
}
installPackagesTask(host, false, options.directory, options.packageManager);
installPackagesTask(tree, false, options.directory, options.packageManager);
// TODO: move all of these into create-nx-workspace
if (options.preset !== Preset.NPM && !options.isCustomPreset) {
await generatePreset(host, options);
await generatePreset(tree, options);
}
};
}
Expand Down
37 changes: 29 additions & 8 deletions packages/workspace/src/generators/preset/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '@nx/devkit';
import { Schema } from './schema';
import { Preset } from '../utils/presets';
import { join } from 'path';

export async function presetGenerator(tree: Tree, options: Schema) {
options = normalizeOptions(options);
Expand All @@ -29,6 +30,8 @@ async function createPreset(tree: Tree, options: Schema) {

return angularApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
standalone: options.standaloneApi,
Expand All @@ -42,6 +45,8 @@ async function createPreset(tree: Tree, options: Schema) {

return angularApplicationGenerator(tree, {
name: options.name,
directory: '.',
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
routing: options.routing,
Expand All @@ -55,6 +60,8 @@ async function createPreset(tree: Tree, options: Schema) {

return reactApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
bundler: options.bundler ?? 'webpack',
Expand All @@ -66,6 +73,8 @@ async function createPreset(tree: Tree, options: Schema) {

return reactApplicationGenerator(tree, {
name: options.name,
directory: '.',
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
rootProject: true,
Expand All @@ -79,6 +88,8 @@ async function createPreset(tree: Tree, options: Schema) {

return nextApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
appDir: options.nextAppDir,
Expand All @@ -89,6 +100,8 @@ async function createPreset(tree: Tree, options: Schema) {
'/next');
return nextApplicationGenerator(tree, {
name: options.name,
directory: '.',
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
appDir: options.nextAppDir,
Expand All @@ -101,6 +114,8 @@ async function createPreset(tree: Tree, options: Schema) {

return webApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
style: options.style,
linter: options.linter,
bundler: 'vite',
Expand All @@ -112,6 +127,8 @@ async function createPreset(tree: Tree, options: Schema) {

return nestApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
e2eTestRunner: options.e2eTestRunner ?? 'jest',
});
Expand All @@ -121,6 +138,8 @@ async function createPreset(tree: Tree, options: Schema) {
} = require('@nx' + '/express');
return expressApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
e2eTestRunner: options.e2eTestRunner ?? 'jest',
});
Expand All @@ -129,31 +148,29 @@ async function createPreset(tree: Tree, options: Schema) {
'/react-native');
return reactNativeApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
e2eTestRunner: options.e2eTestRunner ?? 'detox',
});
} else if (options.preset === Preset.Expo) {
const { expoApplicationGenerator } = require('@nx' + '/expo');
return expoApplicationGenerator(tree, {
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
e2eTestRunner: options.e2eTestRunner ?? 'detox',
});
} else if (options.preset === Preset.TS) {
const c = readNxJson(tree);
const { initGenerator } = require('@nx' + '/js');
c.workspaceLayout = {
appsDir: 'packages',
libsDir: 'packages',
};
updateNxJson(tree, c);
return initGenerator(tree, {});
} else if (options.preset === Preset.TsStandalone) {
const c = readNxJson(tree);
const { libraryGenerator } = require('@nx' + '/js');
updateNxJson(tree, c);
return libraryGenerator(tree, {
name: options.name,
directory: join('packages', options.name),
projectNameAndRootFormat: 'as-provided',
bundler: 'tsc',
unitTestRunner: 'vitest',
testEnvironment: 'node',
Expand All @@ -167,6 +184,8 @@ async function createPreset(tree: Tree, options: Schema) {
return nodeApplicationGenerator(tree, {
bundler,
name: options.name,
directory: '.',
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
standaloneConfig: options.standaloneConfig,
framework: options.framework,
Expand All @@ -181,6 +200,8 @@ async function createPreset(tree: Tree, options: Schema) {
return nodeApplicationGenerator(tree, {
bundler,
name: options.name,
directory: join('apps', options.name),
projectNameAndRootFormat: 'as-provided',
linter: options.linter,
framework: options.framework,
docker: options.docker,
Expand Down