feat(misc): introduce a way to set the project name/root format for all generators (#18971)
This commit is contained in:
parent
0cc6ba996f
commit
bd1b0b70fd
@ -192,6 +192,7 @@ Where new apps + libs should be placed
|
|||||||
#### Type declaration
|
#### Type declaration
|
||||||
|
|
||||||
| Name | Type |
|
| Name | Type |
|
||||||
| :-------- | :------- |
|
| :-------------------------- | :----------------------------- |
|
||||||
| `appsDir` | `string` |
|
| `appsDir?` | `string` |
|
||||||
| `libsDir` | `string` |
|
| `libsDir?` | `string` |
|
||||||
|
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |
|
||||||
|
|||||||
@ -268,9 +268,10 @@ Where new apps + libs should be placed
|
|||||||
#### Type declaration
|
#### Type declaration
|
||||||
|
|
||||||
| Name | Type |
|
| Name | Type |
|
||||||
| :-------- | :------- |
|
| :-------------------------- | :----------------------------- |
|
||||||
| `appsDir` | `string` |
|
| `appsDir?` | `string` |
|
||||||
| `libsDir` | `string` |
|
| `libsDir?` | `string` |
|
||||||
|
| `projectNameAndRootFormat?` | `"as-provided"` \| `"derived"` |
|
||||||
|
|
||||||
#### Inherited from
|
#### Inherited from
|
||||||
|
|
||||||
|
|||||||
@ -558,7 +558,7 @@ describe('Linter', () => {
|
|||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
e2eTestRunner: 'none',
|
e2eTestRunner: 'none',
|
||||||
});
|
});
|
||||||
runCLI(`generate @nx/js:lib ${mylib}`);
|
runCLI(`generate @nx/js:lib ${mylib} --directory libs/${mylib}`);
|
||||||
|
|
||||||
// migrate to flat structure
|
// migrate to flat structure
|
||||||
runCLI(`generate @nx/linter:convert-to-flat-config`);
|
runCLI(`generate @nx/linter:convert-to-flat-config`);
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import {
|
|||||||
RunCmdOpts,
|
RunCmdOpts,
|
||||||
runCommand,
|
runCommand,
|
||||||
} from './command-utils';
|
} from './command-utils';
|
||||||
import { output } from '@nx/devkit';
|
import { NxJsonConfiguration, output } from '@nx/devkit';
|
||||||
import { readFileSync } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
@ -41,6 +41,7 @@ let projName: string;
|
|||||||
export function newProject({
|
export function newProject({
|
||||||
name = uniq('proj'),
|
name = uniq('proj'),
|
||||||
packageManager = getSelectedPackageManager(),
|
packageManager = getSelectedPackageManager(),
|
||||||
|
unsetProjectNameAndRootFormat = true,
|
||||||
} = {}): string {
|
} = {}): string {
|
||||||
try {
|
try {
|
||||||
const projScope = 'proj';
|
const projScope = 'proj';
|
||||||
@ -51,6 +52,13 @@ export function newProject({
|
|||||||
packageManager,
|
packageManager,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (unsetProjectNameAndRootFormat) {
|
||||||
|
updateJson<NxJsonConfiguration>('nx.json', (nxJson) => {
|
||||||
|
delete nxJson.workspaceLayout;
|
||||||
|
return nxJson;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Temporary hack to prevent installing with `--frozen-lockfile`
|
// Temporary hack to prevent installing with `--frozen-lockfile`
|
||||||
if (isCI && packageManager === 'pnpm') {
|
if (isCI && packageManager === 'pnpm') {
|
||||||
updateFile(
|
updateFile(
|
||||||
|
|||||||
@ -348,10 +348,21 @@ describe('determineProjectNameAndRootOptions', () => {
|
|||||||
|
|
||||||
expect(promptSpy).toHaveBeenCalledTimes(2);
|
expect(promptSpy).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
expect(readNxJson(tree).generators['@nx/some-plugin:app']).toEqual({
|
expect(readNxJson(tree).workspaceLayout).toEqual({
|
||||||
projectNameAndRootFormat: 'as-provided',
|
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
|
// restore original interactive mode
|
||||||
restoreOriginalInteractiveMode();
|
restoreOriginalInteractiveMode();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -75,7 +75,9 @@ export async function determineProjectNameAndRootOptions(
|
|||||||
const formats = getProjectNameAndRootFormats(tree, options);
|
const formats = getProjectNameAndRootFormats(tree, options);
|
||||||
const format =
|
const format =
|
||||||
options.projectNameAndRootFormat ??
|
options.projectNameAndRootFormat ??
|
||||||
(await determineFormat(tree, formats, options.callingGenerator));
|
(getDefaultProjectNameAndRootFormat(tree) === 'as-provided'
|
||||||
|
? 'as-provided'
|
||||||
|
: await determineFormat(tree, formats, options.callingGenerator));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...formats[format],
|
...formats[format],
|
||||||
@ -167,11 +169,7 @@ async function determineFormat(
|
|||||||
initial: true,
|
initial: true,
|
||||||
});
|
});
|
||||||
if (saveDefault) {
|
if (saveDefault) {
|
||||||
const nxJson = readNxJson(tree);
|
setProjectNameAndRootFormatDefault(tree);
|
||||||
nxJson.generators ??= {};
|
|
||||||
nxJson.generators[callingGenerator] ??= {};
|
|
||||||
nxJson.generators[callingGenerator].projectNameAndRootFormat = result;
|
|
||||||
updateNxJson(tree, nxJson);
|
|
||||||
} else {
|
} else {
|
||||||
logger.warn(deprecationWarning);
|
logger.warn(deprecationWarning);
|
||||||
}
|
}
|
||||||
@ -183,6 +181,18 @@ async function determineFormat(
|
|||||||
return result;
|
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(
|
function getProjectNameAndRootFormats(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: ProjectGenerationOptions
|
options: ProjectGenerationOptions
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export function toNodeApplicationGeneratorOptions(
|
|||||||
name: options.name,
|
name: options.name,
|
||||||
directory: options.directory,
|
directory: options.directory,
|
||||||
frontendProject: options.frontendProject,
|
frontendProject: options.frontendProject,
|
||||||
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
skipPackageJson: options.skipPackageJson,
|
skipPackageJson: options.skipPackageJson,
|
||||||
|
|||||||
@ -56,6 +56,11 @@
|
|||||||
"appsDir": {
|
"appsDir": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Default folder name for apps."
|
"description": "Default folder name for apps."
|
||||||
|
},
|
||||||
|
"projectNameAndRootFormat": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Default method of handling arguments for generating projects",
|
||||||
|
"enum": ["as-provided", "derived"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"additionalProperties": false
|
"additionalProperties": false
|
||||||
|
|||||||
@ -86,8 +86,9 @@ export interface NxJsonConfiguration<T = '*' | string[]> {
|
|||||||
* Where new apps + libs should be placed
|
* Where new apps + libs should be placed
|
||||||
*/
|
*/
|
||||||
workspaceLayout?: {
|
workspaceLayout?: {
|
||||||
libsDir: string;
|
libsDir?: string;
|
||||||
appsDir: string;
|
appsDir?: string;
|
||||||
|
projectNameAndRootFormat?: 'as-provided' | 'derived';
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* Available Task Runners
|
* Available Task Runners
|
||||||
|
|||||||
@ -53,5 +53,8 @@ exports[`new should generate an empty nx.json 1`] = `
|
|||||||
"runner": "nx/tasks-runners/default",
|
"runner": "nx/tasks-runners/default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"workspaceLayout": {
|
||||||
|
"projectNameAndRootFormat": "as-provided",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -122,6 +122,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
|
|||||||
"runner": "nx/tasks-runners/default",
|
"runner": "nx/tasks-runners/default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"workspaceLayout": {
|
||||||
|
"projectNameAndRootFormat": "as-provided",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
const validateNxJson = ajv.compile(nxSchema);
|
const validateNxJson = ajv.compile(nxSchema);
|
||||||
@ -174,6 +177,9 @@ describe('@nx/workspace:generateWorkspaceFiles', () => {
|
|||||||
"runner": "nx/tasks-runners/default",
|
"runner": "nx/tasks-runners/default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"workspaceLayout": {
|
||||||
|
"projectNameAndRootFormat": "as-provided",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -98,6 +98,9 @@ function createNxJson(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workspaceLayout: {
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
nxJson.targetDefaults = {
|
nxJson.targetDefaults = {
|
||||||
|
|||||||
@ -41,27 +41,28 @@ export interface NormalizedSchema extends Schema {
|
|||||||
isCustomPreset: boolean;
|
isCustomPreset: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function newGenerator(host: Tree, opts: Schema) {
|
export async function newGenerator(tree: Tree, opts: Schema) {
|
||||||
const options = normalizeOptions(opts);
|
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);
|
addPresetDependencies(tree, options);
|
||||||
addCloudDependencies(host, options);
|
|
||||||
|
addCloudDependencies(tree, options);
|
||||||
|
|
||||||
return async () => {
|
return async () => {
|
||||||
const pmc = getPackageManagerCommand(options.packageManager);
|
const pmc = getPackageManagerCommand(options.packageManager);
|
||||||
if (pmc.preInstall) {
|
if (pmc.preInstall) {
|
||||||
execSync(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',
|
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
|
// TODO: move all of these into create-nx-workspace
|
||||||
if (options.preset !== Preset.NPM && !options.isCustomPreset) {
|
if (options.preset !== Preset.NPM && !options.isCustomPreset) {
|
||||||
await generatePreset(host, options);
|
await generatePreset(tree, options);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import {
|
|||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { Preset } from '../utils/presets';
|
import { Preset } from '../utils/presets';
|
||||||
|
import { join } from 'path';
|
||||||
|
|
||||||
export async function presetGenerator(tree: Tree, options: Schema) {
|
export async function presetGenerator(tree: Tree, options: Schema) {
|
||||||
options = normalizeOptions(options);
|
options = normalizeOptions(options);
|
||||||
@ -29,6 +30,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return angularApplicationGenerator(tree, {
|
return angularApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
standalone: options.standaloneApi,
|
standalone: options.standaloneApi,
|
||||||
@ -42,6 +45,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return angularApplicationGenerator(tree, {
|
return angularApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: '.',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
routing: options.routing,
|
routing: options.routing,
|
||||||
@ -55,6 +60,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return reactApplicationGenerator(tree, {
|
return reactApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
bundler: options.bundler ?? 'webpack',
|
bundler: options.bundler ?? 'webpack',
|
||||||
@ -66,6 +73,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return reactApplicationGenerator(tree, {
|
return reactApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: '.',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
rootProject: true,
|
rootProject: true,
|
||||||
@ -79,6 +88,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return nextApplicationGenerator(tree, {
|
return nextApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
appDir: options.nextAppDir,
|
appDir: options.nextAppDir,
|
||||||
@ -89,6 +100,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
'/next');
|
'/next');
|
||||||
return nextApplicationGenerator(tree, {
|
return nextApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: '.',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
appDir: options.nextAppDir,
|
appDir: options.nextAppDir,
|
||||||
@ -101,6 +114,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return webApplicationGenerator(tree, {
|
return webApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
style: options.style,
|
style: options.style,
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
bundler: 'vite',
|
bundler: 'vite',
|
||||||
@ -112,6 +127,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
|
|
||||||
return nestApplicationGenerator(tree, {
|
return nestApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
||||||
});
|
});
|
||||||
@ -121,6 +138,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
} = require('@nx' + '/express');
|
} = require('@nx' + '/express');
|
||||||
return expressApplicationGenerator(tree, {
|
return expressApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
||||||
});
|
});
|
||||||
@ -129,6 +148,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
'/react-native');
|
'/react-native');
|
||||||
return reactNativeApplicationGenerator(tree, {
|
return reactNativeApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'detox',
|
e2eTestRunner: options.e2eTestRunner ?? 'detox',
|
||||||
});
|
});
|
||||||
@ -136,24 +157,20 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
const { expoApplicationGenerator } = require('@nx' + '/expo');
|
const { expoApplicationGenerator } = require('@nx' + '/expo');
|
||||||
return expoApplicationGenerator(tree, {
|
return expoApplicationGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'detox',
|
e2eTestRunner: options.e2eTestRunner ?? 'detox',
|
||||||
});
|
});
|
||||||
} else if (options.preset === Preset.TS) {
|
} else if (options.preset === Preset.TS) {
|
||||||
const c = readNxJson(tree);
|
|
||||||
const { initGenerator } = require('@nx' + '/js');
|
const { initGenerator } = require('@nx' + '/js');
|
||||||
c.workspaceLayout = {
|
|
||||||
appsDir: 'packages',
|
|
||||||
libsDir: 'packages',
|
|
||||||
};
|
|
||||||
updateNxJson(tree, c);
|
|
||||||
return initGenerator(tree, {});
|
return initGenerator(tree, {});
|
||||||
} else if (options.preset === Preset.TsStandalone) {
|
} else if (options.preset === Preset.TsStandalone) {
|
||||||
const c = readNxJson(tree);
|
|
||||||
const { libraryGenerator } = require('@nx' + '/js');
|
const { libraryGenerator } = require('@nx' + '/js');
|
||||||
updateNxJson(tree, c);
|
|
||||||
return libraryGenerator(tree, {
|
return libraryGenerator(tree, {
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('packages', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
bundler: 'tsc',
|
bundler: 'tsc',
|
||||||
unitTestRunner: 'vitest',
|
unitTestRunner: 'vitest',
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
@ -167,6 +184,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
return nodeApplicationGenerator(tree, {
|
return nodeApplicationGenerator(tree, {
|
||||||
bundler,
|
bundler,
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: '.',
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
standaloneConfig: options.standaloneConfig,
|
standaloneConfig: options.standaloneConfig,
|
||||||
framework: options.framework,
|
framework: options.framework,
|
||||||
@ -181,6 +200,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
return nodeApplicationGenerator(tree, {
|
return nodeApplicationGenerator(tree, {
|
||||||
bundler,
|
bundler,
|
||||||
name: options.name,
|
name: options.name,
|
||||||
|
directory: join('apps', options.name),
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
framework: options.framework,
|
framework: options.framework,
|
||||||
docker: options.docker,
|
docker: options.docker,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user