Skip to content

Commit

Permalink
feat(nx-plugin): use helper to determine project name and root in pro…
Browse files Browse the repository at this point in the history
…ject generators (#18739)
  • Loading branch information
leosvelperez authored Aug 22, 2023
1 parent 1b0439b commit 016c89f
Show file tree
Hide file tree
Showing 16 changed files with 210 additions and 89 deletions.
9 changes: 7 additions & 2 deletions docs/generated/packages/plugin/generators/create-package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-package",
"factory": "./src/generators/create-package/create-package",
"factory": "./src/generators/create-package/create-package#createPackageGeneratorInternal",
"schema": {
"$schema": "http://json-schema.org/schema",
"cli": "nx",
Expand Down Expand Up @@ -35,6 +35,11 @@
"type": "string",
"description": "A directory where the app is placed."
},
"projectNameAndRootFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"linter": {
"description": "The tool to use for running lint checks.",
"type": "string",
Expand Down Expand Up @@ -70,7 +75,7 @@
"presets": []
},
"description": "Create a package which can be used by npx to create a new workspace",
"implementation": "/packages/plugin/src/generators/create-package/create-package.ts",
"implementation": "/packages/plugin/src/generators/create-package/create-package#createPackageGeneratorInternal.ts",
"aliases": [],
"hidden": false,
"path": "/packages/plugin/src/generators/create-package/schema.json",
Expand Down
9 changes: 7 additions & 2 deletions docs/generated/packages/plugin/generators/e2e-project.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "e2e-project",
"factory": "./src/generators/e2e-project/e2e",
"factory": "./src/generators/e2e-project/e2e#e2eProjectGeneratorInternal",
"schema": {
"$schema": "http://json-schema.org/schema",
"cli": "nx",
Expand All @@ -24,6 +24,11 @@
"type": "string",
"description": "the directory where the plugin is placed."
},
"projectNameAndRootFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"pluginOutputPath": {
"type": "string",
"description": "the output path of the plugin after it builds.",
Expand Down Expand Up @@ -52,7 +57,7 @@
"presets": []
},
"description": "Create a E2E application for a Nx Plugin.",
"implementation": "/packages/plugin/src/generators/e2e-project/e2e.ts",
"implementation": "/packages/plugin/src/generators/e2e-project/e2e#e2eProjectGeneratorInternal.ts",
"aliases": [],
"hidden": false,
"path": "/packages/plugin/src/generators/e2e-project/schema.json",
Expand Down
12 changes: 9 additions & 3 deletions docs/generated/packages/plugin/generators/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "plugin",
"factory": "./src/generators/plugin/plugin",
"factory": "./src/generators/plugin/plugin#pluginGeneratorInternal",
"schema": {
"$schema": "http://json-schema.org/schema",
"cli": "nx",
Expand All @@ -20,12 +20,18 @@
"description": "Plugin name",
"$default": { "$source": "argv", "index": 0 },
"x-prompt": "What name would you like to use for the plugin?",
"x-priority": "important"
"x-priority": "important",
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$"
},
"directory": {
"type": "string",
"description": "A directory where the plugin is placed."
},
"projectNameAndRootFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"importPath": {
"type": "string",
"description": "How the plugin will be published, like `@myorg/my-awesome-plugin`. Note this must be a valid NPM name.",
Expand Down Expand Up @@ -98,7 +104,7 @@
"presets": []
},
"description": "Create a Nx Plugin.",
"implementation": "/packages/plugin/src/generators/plugin/plugin.ts",
"implementation": "/packages/plugin/src/generators/plugin/plugin#pluginGeneratorInternal.ts",
"aliases": [],
"hidden": false,
"path": "/packages/plugin/src/generators/plugin/schema.json",
Expand Down
39 changes: 39 additions & 0 deletions e2e/plugin/src/nx-plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,4 +434,43 @@ describe('Nx Plugin', () => {
)
).toThrow();
});

it('should support the new name and root format', async () => {
const plugin = uniq('plugin');
const createAppName = `create-${plugin}-app`;

runCLI(
`generate @nx/plugin:plugin ${plugin} --e2eTestRunner jest --publishable --project-name-and-root-format=as-provided`
);

// check files are generated without the layout directory ("libs/") and
// using the project name as the directory when no directory is provided
checkFilesExist(`${plugin}/src/index.ts`);
// check build works
expect(runCLI(`build ${plugin}`)).toContain(
`Successfully ran target build for project ${plugin}`
);
// check tests pass
const appTestResult = runCLI(`test ${plugin}`);
expect(appTestResult).toContain(
`Successfully ran target test for project ${plugin}`
);

runCLI(
`generate @nx/plugin:create-package ${createAppName} --project=${plugin} --e2eProject=${plugin}-e2e --project-name-and-root-format=as-provided`
);

// check files are generated without the layout directory ("libs/") and
// using the project name as the directory when no directory is provided
checkFilesExist(`${plugin}/src/generators/preset`, `${createAppName}`);
// check build works
expect(runCLI(`build ${createAppName}`)).toContain(
`Successfully ran target build for project ${createAppName}`
);
// check tests pass
const libTestResult = runCLI(`test ${createAppName}`);
expect(libTestResult).toContain(
`Successfully ran target test for project ${createAppName}`
);
});
});
6 changes: 3 additions & 3 deletions packages/plugin/generators.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
"extends": ["@nx/workspace"],
"generators": {
"plugin": {
"factory": "./src/generators/plugin/plugin",
"factory": "./src/generators/plugin/plugin#pluginGeneratorInternal",
"schema": "./src/generators/plugin/schema.json",
"description": "Create a Nx Plugin."
},
"create-package": {
"factory": "./src/generators/create-package/create-package",
"factory": "./src/generators/create-package/create-package#createPackageGeneratorInternal",
"schema": "./src/generators/create-package/schema.json",
"description": "Create a package which can be used by npx to create a new workspace"
},
"e2e-project": {
"factory": "./src/generators/e2e-project/e2e",
"factory": "./src/generators/e2e-project/e2e#e2eProjectGeneratorInternal",
"schema": "./src/generators/e2e-project/schema.json",
"description": "Create a E2E application for a Nx Plugin."
},
Expand Down
12 changes: 11 additions & 1 deletion packages/plugin/src/generators/create-package/create-package.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,20 @@ import { join } from 'path';
export async function createPackageGenerator(
host: Tree,
schema: CreatePackageSchema
) {
return await createPackageGeneratorInternal(host, {
projectNameAndRootFormat: 'derived',
...schema,
});
}

export async function createPackageGeneratorInternal(
host: Tree,
schema: CreatePackageSchema
) {
const tasks: GeneratorCallback[] = [];

const options = normalizeSchema(host, schema);
const options = await normalizeSchema(host, schema);
const pluginPackageName = await addPresetGenerator(host, options);

const installTask = addDependenciesToPackageJson(
Expand Down
2 changes: 2 additions & 0 deletions packages/plugin/src/generators/create-package/schema.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-directory-utils';
import type { Linter } from '@nx/linter';

export interface CreatePackageSchema {
Expand All @@ -6,6 +7,7 @@ export interface CreatePackageSchema {

// options to create cli package, passed to js library generator
directory?: string;
projectNameAndRootFormat?: ProjectNameAndRootFormat;
skipFormat: boolean;
tags?: string;
unitTestRunner: 'jest' | 'none';
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin/src/generators/create-package/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
"type": "string",
"description": "A directory where the app is placed."
},
"projectNameAndRootFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"linter": {
"description": "The tool to use for running lint checks.",
"type": "string",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,36 @@
import {
extractLayoutDirectory,
getWorkspaceLayout,
joinPathFragments,
names,
Tree,
} from '@nx/devkit';
import { Tree } from '@nx/devkit';
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
import { CreatePackageSchema } from '../schema';

export interface NormalizedSchema extends CreatePackageSchema {
bundler: 'swc' | 'tsc';
libsDir: string;
projectName: string;
projectRoot: string;
projectDirectory: string;
}

export function normalizeSchema(
export async function normalizeSchema(
host: Tree,
schema: CreatePackageSchema
): NormalizedSchema {
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
schema.directory
);
const { libsDir: defaultLibsDir } = getWorkspaceLayout(host);
const libsDir = layoutDirectory ?? defaultLibsDir;
const name = names(schema.name).fileName;
const fullProjectDirectory = projectDirectory
? `${names(projectDirectory).fileName}/${name}`
: name;
const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-');
const projectRoot = joinPathFragments(libsDir, fullProjectDirectory);
): Promise<NormalizedSchema> {
const {
projectName,
names: projectNames,
projectRoot,
projectNameAndRootFormat,
} = await determineProjectNameAndRootOptions(host, {
name: schema.name,
projectType: 'library',
directory: schema.directory,
projectNameAndRootFormat: schema.projectNameAndRootFormat,
callingGenerator: '@nx/plugin:create-package',
});
schema.projectNameAndRootFormat = projectNameAndRootFormat;

return {
...schema,
bundler: schema.compiler ?? 'tsc',
libsDir,
projectName,
projectRoot,
name,
projectDirectory: fullProjectDirectory,
name: projectNames.projectSimpleName,
};
}
57 changes: 43 additions & 14 deletions packages/plugin/src/generators/e2e-project/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ import {
runTasksInSerial,
updateProjectConfiguration,
} from '@nx/devkit';
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
import { addPropertyToJestConfig, configurationGenerator } from '@nx/jest';
import { getRelativePathToRootTsConfig } from '@nx/js';
import { setupVerdaccio } from '@nx/js/src/generators/setup-verdaccio/generator';
import { addLocalRegistryScripts } from '@nx/js/src/utils/add-local-registry-scripts';
import { join } from 'path';
import { Linter, lintProjectGenerator } from '@nx/linter';

import { join } from 'path';
import type { Schema } from './schema';

interface NormalizedSchema extends Schema {
Expand All @@ -32,20 +32,42 @@ interface NormalizedSchema extends Schema {
linter: Linter;
}

function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
options.projectDirectory
);
const { appsDir: defaultAppsDir } = getWorkspaceLayout(host);
const appsDir = layoutDirectory ?? defaultAppsDir;

async function normalizeOptions(
host: Tree,
options: Schema
): Promise<NormalizedSchema> {
const projectName = options.rootProject ? 'e2e' : `${options.pluginName}-e2e`;
const projectRoot =
projectDirectory && !options.rootProject
? joinPathFragments(appsDir, `${projectDirectory}-e2e`)
: options.rootProject

let projectRoot: string;
if (options.projectNameAndRootFormat === 'as-provided') {
const projectNameAndRootOptions = await determineProjectNameAndRootOptions(
host,
{
name: projectName,
projectType: 'application',
directory:
options.rootProject || !options.projectDirectory
? projectName
: `${options.projectDirectory}-e2e`,
projectNameAndRootFormat: `as-provided`,
callingGenerator: '@nx/plugin:e2e-project',
}
);
projectRoot = projectNameAndRootOptions.projectRoot;
} else {
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
options.projectDirectory
);
const { appsDir: defaultAppsDir } = getWorkspaceLayout(host);
const appsDir = layoutDirectory ?? defaultAppsDir;

projectRoot = options.rootProject
? projectName
: projectDirectory
? joinPathFragments(appsDir, `${projectDirectory}-e2e`)
: joinPathFragments(appsDir, projectName);
}

const pluginPropertyName = names(options.pluginName).propertyName;

return {
Expand Down Expand Up @@ -158,10 +180,17 @@ async function addLintingToApplication(
}

export async function e2eProjectGenerator(host: Tree, schema: Schema) {
return await e2eProjectGeneratorInternal(host, {
projectNameAndRootFormat: 'derived',
...schema,
});
}

export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) {
const tasks: GeneratorCallback[] = [];

validatePlugin(host, schema.pluginName);
const options = normalizeOptions(host, schema);
const options = await normalizeOptions(host, schema);
addFiles(host, options);
tasks.push(
await setupVerdaccio(host, {
Expand Down
4 changes: 3 additions & 1 deletion packages/plugin/src/generators/e2e-project/schema.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Linter } from '@nx/linter';
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-directory-utils';
import type { Linter } from '@nx/linter';

export interface Schema {
pluginName: string;
npmPackageName: string;
projectDirectory?: string;
projectNameAndRootFormat?: ProjectNameAndRootFormat;
pluginOutputPath?: string;
jestConfig?: string;
linter?: Linter;
Expand Down
5 changes: 5 additions & 0 deletions packages/plugin/src/generators/e2e-project/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
"type": "string",
"description": "the directory where the plugin is placed."
},
"projectNameAndRootFormat": {
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).",
"type": "string",
"enum": ["as-provided", "derived"]
},
"pluginOutputPath": {
"type": "string",
"description": "the output path of the plugin after it builds.",
Expand Down
Loading

1 comment on commit 016c89f

@vercel
Copy link

@vercel vercel bot commented on 016c89f Aug 22, 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-dev-nrwl.vercel.app
nx-five.vercel.app

Please sign in to comment.