Skip to content

Commit

Permalink
feat(misc): introduce a way to set the project name/root format for a…
Browse files Browse the repository at this point in the history
…ll generators (#18971)
  • Loading branch information
FrozenPandaz authored Sep 1, 2023
1 parent 0cc6ba9 commit bd1b0b7
Show file tree
Hide file tree
Showing 14 changed files with 107 additions and 35 deletions.
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

1 comment on commit bd1b0b7

@vercel
Copy link

@vercel vercel bot commented on bd1b0b7 Sep 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-git-master-nrwl.vercel.app
nx.dev
nx-five.vercel.app
nx-dev-nrwl.vercel.app

Please sign in to comment.