feat(misc): save directory and name format to nx json defaults (#18683)

This commit is contained in:
Craigory Coppola 2023-08-17 17:48:42 -04:00 committed by GitHub
parent 61d73fc907
commit e2ff519db2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 84 additions and 4 deletions

View File

@ -21,6 +21,7 @@ export async function normalizeOptions(
directory: options.directory,
projectNameAndRootFormat: options.projectNameAndRootFormat,
rootProject: options.rootProject,
callingGenerator: '@nx/angular:application',
});
options.rootProject = appProjectRoot === '.';
options.projectNameAndRootFormat = projectNameAndRootFormat;
@ -34,6 +35,7 @@ export async function normalizeOptions(
directory: options.directory,
projectNameAndRootFormat: options.projectNameAndRootFormat,
rootProject: options.rootProject,
callingGenerator: '@nx/angular:application',
});
e2eProjectName = projectNameAndRoot.projectName;
e2eProjectRoot = projectNameAndRoot.projectRoot;

View File

@ -51,6 +51,7 @@ export async function hostInternal(tree: Tree, options: Schema) {
projectType: 'application',
directory: options.directory,
projectNameAndRootFormat: options.projectNameAndRootFormat,
callingGenerator: '@nx/angular:host',
});
options.projectNameAndRootFormat = projectNameAndRootFormat;

View File

@ -38,6 +38,7 @@ export async function normalizeOptions(
directory: options.directory,
importPath: options.importPath,
projectNameAndRootFormat: options.projectNameAndRootFormat,
callingGenerator: '@nx/angular:library',
});
const fileName = options.simpleName

View File

@ -42,6 +42,7 @@ export async function remoteInternal(tree: Tree, options: Schema) {
projectType: 'application',
directory: options.directory,
projectNameAndRootFormat: options.projectNameAndRootFormat,
callingGenerator: '@nx/angular:remote',
});
options.projectNameAndRootFormat = projectNameAndRootFormat;

View File

@ -250,6 +250,7 @@ async function normalizeOptions(
projectNameAndRootFormat: isRootProject
? 'as-provided'
: options.projectNameAndRootFormat,
callingGenerator: '@nx/cypress:cypress-project',
}
);

View File

@ -2,6 +2,7 @@ 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', () => {
@ -40,6 +41,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toStrictEqual({
@ -60,6 +62,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toEqual({
@ -81,6 +84,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
importPath: '@custom-scope/lib-name',
callingGenerator: '',
});
expect(result).toEqual({
@ -104,6 +108,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: '@scope/libName',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toEqual({
@ -129,6 +134,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result).toEqual({
@ -154,6 +160,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result.importPath).toBe('@proj/lib-name');
@ -166,6 +173,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
})
).rejects.toThrowError();
});
@ -176,6 +184,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'derived',
callingGenerator: '',
});
expect(result).toEqual({
@ -197,6 +206,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'derived',
callingGenerator: '',
})
).rejects.toThrowError();
});
@ -211,6 +221,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'derived',
rootProject: true,
callingGenerator: '',
});
expect(result).toEqual({
@ -236,6 +247,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result.importPath).toBe('@proj/lib-name');
@ -252,6 +264,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: 'libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '',
});
expect(promptSpy).toHaveBeenCalled();
@ -275,6 +288,32 @@ 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).generators['@nx/some-plugin:app']).toEqual({
projectNameAndRootFormat: 'as-provided',
});
// 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();
@ -284,6 +323,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: '@scope/libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '',
});
expect(promptSpy).not.toHaveBeenCalled();
@ -315,6 +355,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toEqual({
@ -335,6 +376,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toEqual({
@ -356,6 +398,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
importPath: '@custom-scope/lib-name',
callingGenerator: '',
});
expect(result).toEqual({
@ -380,6 +423,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: '@scope/libName',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
});
expect(result).toEqual({
@ -405,6 +449,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result).toEqual({
@ -430,6 +475,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result.importPath).toBe('@proj/lib-name');
@ -442,6 +488,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
callingGenerator: '',
})
).rejects.toThrowError();
});
@ -452,6 +499,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'derived',
callingGenerator: '',
});
expect(result).toEqual({
@ -473,6 +521,7 @@ describe('determineProjectNameAndRootOptions', () => {
directory: 'shared',
projectType: 'library',
projectNameAndRootFormat: 'derived',
callingGenerator: '',
})
).rejects.toThrowError();
});
@ -488,6 +537,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'derived',
rootProject: true,
callingGenerator: '',
});
expect(result).toEqual({
@ -513,6 +563,7 @@ describe('determineProjectNameAndRootOptions', () => {
projectType: 'library',
projectNameAndRootFormat: 'as-provided',
rootProject: true,
callingGenerator: '',
});
expect(result.importPath).toBe('@proj/lib-name');
@ -529,6 +580,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: 'libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '',
});
expect(promptSpy).toHaveBeenCalled();
@ -561,6 +613,7 @@ describe('determineProjectNameAndRootOptions', () => {
name: '@scope/libName',
projectType: 'library',
directory: 'shared',
callingGenerator: '',
});
expect(promptSpy).not.toHaveBeenCalled();

View File

@ -8,12 +8,13 @@ import {
} from '../utils/get-workspace-layout';
import { names } from '../utils/names';
const { joinPathFragments, readJson, readNxJson } = requireNx();
const { joinPathFragments, readJson, readNxJson, updateNxJson } = requireNx();
export type ProjectNameAndRootFormat = 'as-provided' | 'derived';
export type ProjectGenerationOptions = {
name: string;
projectType: ProjectType;
callingGenerator: string;
directory?: string;
importPath?: string;
projectNameAndRootFormat?: ProjectNameAndRootFormat;
@ -65,7 +66,8 @@ export async function determineProjectNameAndRootOptions(
validateName(options.name, options.projectNameAndRootFormat);
const formats = getProjectNameAndRootFormats(tree, options);
const format =
options.projectNameAndRootFormat ?? (await determineFormat(formats));
options.projectNameAndRootFormat ??
(await determineFormat(tree, formats, options.callingGenerator));
return {
...formats[format],
@ -104,7 +106,9 @@ function validateName(
}
async function determineFormat(
formats: ProjectNameAndRootFormats
tree: Tree,
formats: ProjectNameAndRootFormats,
callingGenerator: string
): Promise<ProjectNameAndRootFormat> {
if (!formats.derived) {
return 'as-provided';
@ -123,7 +127,7 @@ async function determineFormat(
Root: ${formats['derived'].projectRoot}`;
const derivedSelectedValue = `${formats['derived'].projectName} @ ${formats['derived'].projectRoot} (This was derived from the folder structure. Please provide the exact name and directory in the future)`;
return await prompt<{ format: ProjectNameAndRootFormat }>({
const result = await prompt<{ format: ProjectNameAndRootFormat }>({
type: 'select',
name: 'format',
message:
@ -142,6 +146,22 @@ async function determineFormat(
}).then(({ format }) =>
format === asProvidedSelectedValue ? 'as-provided' : 'derived'
);
if (result === 'as-provided' && callingGenerator) {
const { saveDefault } = await prompt<{ saveDefault: boolean }>({
type: 'confirm',
message: 'Would you like to save this layout as a default?',
name: 'saveDefault',
});
if (saveDefault) {
const nxJson = readNxJson(tree);
nxJson.generators ??= {};
nxJson.generators[callingGenerator] ??= {};
nxJson.generators[callingGenerator].projectNameAndRootFormat = result;
updateNxJson(tree, nxJson);
}
}
return result;
}
function getProjectNameAndRootFormats(

View File

@ -550,6 +550,7 @@ async function normalizeOptions(
importPath: options.importPath,
projectNameAndRootFormat: options.projectNameAndRootFormat,
rootProject: options.rootProject,
callingGenerator: '@nx/js:library',
});
options.rootProject = projectRoot === '.';
const fileName = getCaseAwareFileName({