feat(misc): introduce a way to set the project name/root format for all generators (#18971)

This commit is contained in:
Jason Jean 2023-09-01 16:58:14 -04:00 committed by GitHub
parent 0cc6ba996f
commit bd1b0b70fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 107 additions and 35 deletions

View File

@ -192,6 +192,7 @@ Where new apps + libs should be placed
#### Type declaration
| Name | Type |
| :-------- | :------- |
| `appsDir` | `string` |
| `libsDir` | `string` |
| :-------------------------- | :----------------------------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |

View File

@ -268,9 +268,10 @@ Where new apps + libs should be placed
#### Type declaration
| Name | Type |
| :-------- | :------- |
| `appsDir` | `string` |
| `libsDir` | `string` |
| :-------------------------- | :----------------------------- |
| `appsDir?` | `string` |
| `libsDir?` | `string` |
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |
#### Inherited from

View File

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

View File

@ -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';
@ -41,6 +41,7 @@ let projName: string;
export function newProject({
name = uniq('proj'),
packageManager = getSelectedPackageManager(),
unsetProjectNameAndRootFormat = true,
} = {}): string {
try {
const projScope = 'proj';
@ -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(

View File

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

View File

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

View File

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

View File

@ -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

View File

@ -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

View File

@ -53,5 +53,8 @@ exports[`new should generate an empty nx.json 1`] = `
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`;

View File

@ -122,6 +122,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`);
const validateNxJson = ajv.compile(nxSchema);
@ -174,6 +177,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
"runner": "nx/tasks-runners/default",
},
},
"workspaceLayout": {
"projectNameAndRootFormat": "as-provided",
},
}
`);
});

View File

@ -98,6 +98,9 @@ function createNxJson(
},
},
},
workspaceLayout: {
projectNameAndRootFormat: 'as-provided',
},
};
nxJson.targetDefaults = {

View File

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

View File

@ -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);
@ -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,
@ -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,
@ -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',
@ -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,
@ -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,
@ -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,
@ -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',
@ -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',
});
@ -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',
});
@ -129,6 +148,8 @@ 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',
});
@ -136,24 +157,20 @@ async function createPreset(tree: Tree, options: Schema) {
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',
@ -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,
@ -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,