feat(node): use helper to determine project name and root directory in project generators (#18620)
Co-authored-by: FrozenPandaz <jasonjean1993@gmail.com>
This commit is contained in:
parent
7900d56ff2
commit
d56605522b
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "application",
|
"name": "application",
|
||||||
"factory": "./src/generators/application/application",
|
"factory": "./src/generators/application/application#applicationGeneratorInternal",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
@ -14,13 +14,19 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"$default": { "$source": "argv", "index": 0 },
|
"$default": { "$source": "argv", "index": 0 },
|
||||||
"x-prompt": "What name would you like to use for the node application?",
|
"x-prompt": "What name would you like to use for the node application?",
|
||||||
"x-priority": "important"
|
"x-priority": "important",
|
||||||
|
"pattern": "^[a-zA-Z][^:]*$"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
"description": "The directory of the new application.",
|
"description": "The directory of the new application.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -131,7 +137,7 @@
|
|||||||
"aliases": ["app"],
|
"aliases": ["app"],
|
||||||
"x-type": "application",
|
"x-type": "application",
|
||||||
"description": "Create a node application.",
|
"description": "Create a node application.",
|
||||||
"implementation": "/packages/node/src/generators/application/application.ts",
|
"implementation": "/packages/node/src/generators/application/application#applicationGeneratorInternal.ts",
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"path": "/packages/node/src/generators/application/schema.json",
|
"path": "/packages/node/src/generators/application/schema.json",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "library",
|
"name": "library",
|
||||||
"factory": "./src/generators/library/library",
|
"factory": "./src/generators/library/library#libraryGeneratorInternal",
|
||||||
"schema": {
|
"schema": {
|
||||||
"$schema": "http://json-schema.org/schema",
|
"$schema": "http://json-schema.org/schema",
|
||||||
"cli": "nx",
|
"cli": "nx",
|
||||||
@ -19,13 +19,19 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Library name",
|
"description": "Library name",
|
||||||
"$default": { "$source": "argv", "index": 0 },
|
"$default": { "$source": "argv", "index": 0 },
|
||||||
"x-prompt": "What name would you like to use for the library?"
|
"x-prompt": "What name would you like to use for the library?",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "A directory where the lib is placed",
|
"description": "A directory where the lib is placed",
|
||||||
"alias": "dir"
|
"alias": "dir"
|
||||||
},
|
},
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
"simpleModuleName": {
|
"simpleModuleName": {
|
||||||
"description": "Keep the module name simple (when using `--directory`).",
|
"description": "Keep the module name simple (when using `--directory`).",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@ -131,7 +137,7 @@
|
|||||||
"aliases": ["lib"],
|
"aliases": ["lib"],
|
||||||
"x-type": "library",
|
"x-type": "library",
|
||||||
"description": "Create a node library.",
|
"description": "Create a node library.",
|
||||||
"implementation": "/packages/node/src/generators/library/library.ts",
|
"implementation": "/packages/node/src/generators/library/library#libraryGeneratorInternal.ts",
|
||||||
"hidden": false,
|
"hidden": false,
|
||||||
"path": "/packages/node/src/generators/library/schema.json",
|
"path": "/packages/node/src/generators/library/schema.json",
|
||||||
"type": "generator"
|
"type": "generator"
|
||||||
|
|||||||
@ -438,6 +438,52 @@ ${jslib}();
|
|||||||
checkFilesExist(`dist/apps/_should_keep.txt`);
|
checkFilesExist(`dist/apps/_should_keep.txt`);
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
|
it('should support generating projects with the new name and root format', () => {
|
||||||
|
const appName = uniq('app1');
|
||||||
|
const libName = uniq('@my-org/lib1');
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:app ${appName} --project-name-and-root-format=as-provided --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
// check files are generated without the layout directory ("apps/") and
|
||||||
|
// using the project name as the directory when no directory is provided
|
||||||
|
checkFilesExist(`${appName}/src/main.ts`);
|
||||||
|
// check build works
|
||||||
|
expect(runCLI(`build ${appName}`)).toContain(
|
||||||
|
`Successfully ran target build for project ${appName}`
|
||||||
|
);
|
||||||
|
// check tests pass
|
||||||
|
const appTestResult = runCLI(`test ${appName}`);
|
||||||
|
expect(appTestResult).toContain(
|
||||||
|
`Successfully ran target test for project ${appName}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert scoped project names are not supported when --project-name-and-root-format=derived
|
||||||
|
expect(() =>
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:lib ${libName} --buildable --project-name-and-root-format=derived --no-interactive`
|
||||||
|
)
|
||||||
|
).toThrow();
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:lib ${libName} --buildable --project-name-and-root-format=as-provided --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
// check files are generated without the layout directory ("libs/") and
|
||||||
|
// using the project name as the directory when no directory is provided
|
||||||
|
checkFilesExist(`${libName}/src/index.ts`);
|
||||||
|
// check build works
|
||||||
|
expect(runCLI(`build ${libName}`)).toContain(
|
||||||
|
`Successfully ran target build for project ${libName}`
|
||||||
|
);
|
||||||
|
// check tests pass
|
||||||
|
const libTestResult = runCLI(`test ${libName}`);
|
||||||
|
expect(libTestResult).toContain(
|
||||||
|
`Successfully ran target test for project ${libName}`
|
||||||
|
);
|
||||||
|
}, 500_000);
|
||||||
|
|
||||||
describe('NestJS', () => {
|
describe('NestJS', () => {
|
||||||
it('should have plugin output if specified in `tsPlugins`', async () => {
|
it('should have plugin output if specified in `tsPlugins`', async () => {
|
||||||
newProject();
|
newProject();
|
||||||
|
|||||||
@ -11,14 +11,14 @@
|
|||||||
"hidden": true
|
"hidden": true
|
||||||
},
|
},
|
||||||
"application": {
|
"application": {
|
||||||
"factory": "./src/generators/application/application",
|
"factory": "./src/generators/application/application#applicationGeneratorInternal",
|
||||||
"schema": "./src/generators/application/schema.json",
|
"schema": "./src/generators/application/schema.json",
|
||||||
"aliases": ["app"],
|
"aliases": ["app"],
|
||||||
"x-type": "application",
|
"x-type": "application",
|
||||||
"description": "Create a node application."
|
"description": "Create a node application."
|
||||||
},
|
},
|
||||||
"library": {
|
"library": {
|
||||||
"factory": "./src/generators/library/library",
|
"factory": "./src/generators/library/library#libraryGeneratorInternal",
|
||||||
"schema": "./src/generators/library/schema.json",
|
"schema": "./src/generators/library/schema.json",
|
||||||
"aliases": ["lib"],
|
"aliases": ["lib"],
|
||||||
"x-type": "library",
|
"x-type": "library",
|
||||||
|
|||||||
@ -197,7 +197,7 @@ describe('app', () => {
|
|||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
readProjectConfiguration(tree, 'my-dir-my-node-app-e2e')
|
readProjectConfiguration(tree, 'my-dir-my-node-app-e2e')
|
||||||
).toThrow(/Cannot find/);
|
).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update tags', async () => {
|
it('should update tags', async () => {
|
||||||
|
|||||||
@ -3,11 +3,9 @@ import {
|
|||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
ensurePackage,
|
ensurePackage,
|
||||||
extractLayoutDirectory,
|
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
getWorkspaceLayout,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
logger,
|
logger,
|
||||||
names,
|
names,
|
||||||
@ -22,13 +20,13 @@ import {
|
|||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateTsConfigsToJs,
|
updateTsConfigsToJs,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/linter';
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { configurationGenerator } from '@nx/jest';
|
import { configurationGenerator } from '@nx/jest';
|
||||||
|
|
||||||
import { getRelativePathToRootTsConfig, tsConfigBaseOptions } from '@nx/js';
|
import { getRelativePathToRootTsConfig, tsConfigBaseOptions } from '@nx/js';
|
||||||
|
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
||||||
|
import { Linter, lintProjectGenerator } from '@nx/linter';
|
||||||
|
import { mapLintPattern } from '@nx/linter/src/generators/lint-project/lint-project';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { initGenerator } from '../init/init';
|
|
||||||
import {
|
import {
|
||||||
expressTypingsVersion,
|
expressTypingsVersion,
|
||||||
expressVersion,
|
expressVersion,
|
||||||
@ -41,11 +39,9 @@ import {
|
|||||||
nxVersion,
|
nxVersion,
|
||||||
} from '../../utils/versions';
|
} from '../../utils/versions';
|
||||||
import { e2eProjectGenerator } from '../e2e-project/e2e-project';
|
import { e2eProjectGenerator } from '../e2e-project/e2e-project';
|
||||||
|
import { initGenerator } from '../init/init';
|
||||||
import { setupDockerGenerator } from '../setup-docker/setup-docker';
|
import { setupDockerGenerator } from '../setup-docker/setup-docker';
|
||||||
|
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { mapLintPattern } from '@nx/linter/src/generators/lint-project/lint-project';
|
|
||||||
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
@ -364,7 +360,14 @@ function updateTsConfigOptions(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||||
const options = normalizeOptions(tree, schema);
|
return await applicationGeneratorInternal(tree, {
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
...schema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
|
const options = await normalizeOptions(tree, schema);
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
if (options.framework === 'nest') {
|
if (options.framework === 'nest') {
|
||||||
@ -414,6 +417,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
...options,
|
...options,
|
||||||
projectType: options.framework === 'none' ? 'cli' : 'server',
|
projectType: options.framework === 'none' ? 'cli' : 'server',
|
||||||
name: options.rootProject ? 'e2e' : `${options.name}-e2e`,
|
name: options.rootProject ? 'e2e' : `${options.name}-e2e`,
|
||||||
|
directory: options.rootProject ? 'e2e' : `${options.appProjectRoot}-e2e`,
|
||||||
|
projectNameAndRootFormat: 'as-provided',
|
||||||
project: options.name,
|
project: options.name,
|
||||||
port: options.port,
|
port: options.port,
|
||||||
isNest: options.isNest,
|
isNest: options.isNest,
|
||||||
@ -447,21 +452,24 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
async function normalizeOptions(
|
||||||
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
host: Tree,
|
||||||
options.directory
|
options: Schema
|
||||||
);
|
): Promise<NormalizedSchema> {
|
||||||
const appsDir = layoutDirectory ?? getWorkspaceLayout(host).appsDir;
|
const {
|
||||||
|
projectName: appProjectName,
|
||||||
const appDirectory = projectDirectory
|
projectRoot: appProjectRoot,
|
||||||
? `${names(projectDirectory).fileName}/${names(options.name).fileName}`
|
projectNameAndRootFormat,
|
||||||
: names(options.name).fileName;
|
} = await determineProjectNameAndRootOptions(host, {
|
||||||
|
name: options.name,
|
||||||
const appProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
projectType: 'application',
|
||||||
|
directory: options.directory,
|
||||||
const appProjectRoot = options.rootProject
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||||
? '.'
|
rootProject: options.rootProject,
|
||||||
: joinPathFragments(appsDir, appDirectory);
|
callingGenerator: '@nx/node:application',
|
||||||
|
});
|
||||||
|
options.rootProject = appProjectRoot === '.';
|
||||||
|
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||||
|
|
||||||
options.bundler = options.bundler ?? 'esbuild';
|
options.bundler = options.bundler ?? 'esbuild';
|
||||||
options.e2eTestRunner = options.e2eTestRunner ?? 'jest';
|
options.e2eTestRunner = options.e2eTestRunner ?? 'jest';
|
||||||
@ -472,7 +480,7 @@ function normalizeOptions(host: Tree, options: Schema): NormalizedSchema {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
name: names(appProjectName).fileName,
|
name: appProjectName,
|
||||||
frontendProject: options.frontendProject
|
frontendProject: options.frontendProject
|
||||||
? names(options.frontendProject).fileName
|
? names(options.frontendProject).fileName
|
||||||
: undefined,
|
: undefined,
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { Linter } from '@nx/linter';
|
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
import type { Linter } from '@nx/linter';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
skipPackageJson?: boolean;
|
skipPackageJson?: boolean;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
|
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||||
unitTestRunner?: 'jest' | 'none';
|
unitTestRunner?: 'jest' | 'none';
|
||||||
e2eTestRunner?: 'jest' | 'none';
|
e2eTestRunner?: 'jest' | 'none';
|
||||||
linter?: Linter;
|
linter?: Linter;
|
||||||
|
|||||||
@ -14,13 +14,19 @@
|
|||||||
"index": 0
|
"index": 0
|
||||||
},
|
},
|
||||||
"x-prompt": "What name would you like to use for the node application?",
|
"x-prompt": "What name would you like to use for the node application?",
|
||||||
"x-priority": "important"
|
"x-priority": "important",
|
||||||
|
"pattern": "^[a-zA-Z][^:]*$"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
"description": "The directory of the new application.",
|
"description": "The directory of the new application.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files",
|
"description": "Skip formatting files",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import * as path from 'path';
|
|
||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
extractLayoutDirectory,
|
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
getWorkspaceLayout,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
@ -16,19 +13,30 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/linter';
|
import { Linter, lintProjectGenerator } from '@nx/linter';
|
||||||
|
|
||||||
import { Schema } from './schema';
|
|
||||||
import { axiosVersion } from '../../utils/versions';
|
|
||||||
import { join } from 'path';
|
|
||||||
import {
|
import {
|
||||||
globalJavaScriptOverrides,
|
globalJavaScriptOverrides,
|
||||||
globalTypeScriptOverrides,
|
globalTypeScriptOverrides,
|
||||||
} from '@nx/linter/src/generators/init/global-eslint-config';
|
} from '@nx/linter/src/generators/init/global-eslint-config';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { join } from 'path';
|
||||||
|
import { axiosVersion } from '../../utils/versions';
|
||||||
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export async function e2eProjectGenerator(host: Tree, _options: Schema) {
|
export async function e2eProjectGenerator(host: Tree, options: Schema) {
|
||||||
|
return await e2eProjectGeneratorInternal(host, {
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
...options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function e2eProjectGeneratorInternal(
|
||||||
|
host: Tree,
|
||||||
|
_options: Schema
|
||||||
|
) {
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const options = normalizeOptions(host, _options);
|
const options = await normalizeOptions(host, _options);
|
||||||
const appProject = readProjectConfiguration(host, options.project);
|
const appProject = readProjectConfiguration(host, options.project);
|
||||||
|
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
@ -146,25 +154,23 @@ export async function e2eProjectGenerator(host: Tree, _options: Schema) {
|
|||||||
return runTasksInSerial(...tasks);
|
return runTasksInSerial(...tasks);
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(
|
async function normalizeOptions(
|
||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: Schema
|
options: Schema
|
||||||
): Omit<Schema, 'name'> & { e2eProjectRoot: string; e2eProjectName: string } {
|
): Promise<
|
||||||
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
Omit<Schema, 'name'> & { e2eProjectRoot: string; e2eProjectName: string }
|
||||||
options.directory
|
> {
|
||||||
);
|
const { projectName: e2eProjectName, projectRoot: e2eProjectRoot } =
|
||||||
const appsDir = layoutDirectory ?? getWorkspaceLayout(tree).appsDir;
|
await determineProjectNameAndRootOptions(tree, {
|
||||||
const name = options.name ?? `${options.project}-e2e`;
|
name: options.name ?? `${options.project}-e2e`,
|
||||||
|
projectType: 'library',
|
||||||
const appDirectory = projectDirectory
|
directory: options.rootProject ? 'e2e' : options.directory,
|
||||||
? `${names(projectDirectory).fileName}/${names(name).fileName}`
|
projectNameAndRootFormat: options.rootProject
|
||||||
: names(name).fileName;
|
? 'as-provided'
|
||||||
|
: options.projectNameAndRootFormat,
|
||||||
const e2eProjectName = appDirectory.replace(new RegExp('/', 'g'), '-');
|
// this is an internal generator, don't save defaults
|
||||||
|
callingGenerator: null,
|
||||||
const e2eProjectRoot = options.rootProject
|
});
|
||||||
? 'e2e'
|
|
||||||
: joinPathFragments(appsDir, appDirectory);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
|
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
project: string;
|
project: string;
|
||||||
projectType: 'server' | 'cli';
|
projectType: 'server' | 'cli';
|
||||||
directory?: string;
|
directory?: string;
|
||||||
|
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||||
name?: string;
|
name?: string;
|
||||||
port?: number;
|
port?: number;
|
||||||
linter?: 'eslint' | 'none';
|
linter?: 'eslint' | 'none';
|
||||||
|
|||||||
@ -18,6 +18,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"description": "The name of the e2e project. Defaults to the project name with '-e2e' suffix.",
|
"description": "The name of the e2e project. Defaults to the project name with '-e2e' suffix.",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
convertNxGenerator,
|
convertNxGenerator,
|
||||||
extractLayoutDirectory,
|
|
||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
getWorkspaceLayout,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
@ -15,26 +13,31 @@ import {
|
|||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateTsConfigsToJs,
|
updateTsConfigsToJs,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Schema } from './schema';
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||||
|
|
||||||
import { join } from 'path';
|
|
||||||
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
|
||||||
import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
||||||
|
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||||
|
import { join } from 'path';
|
||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
name: string;
|
|
||||||
fileName: string;
|
fileName: string;
|
||||||
|
projectName: string;
|
||||||
projectRoot: string;
|
projectRoot: string;
|
||||||
projectDirectory: string;
|
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
compiler: 'swc' | 'tsc';
|
compiler: 'swc' | 'tsc';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function libraryGenerator(tree: Tree, schema: Schema) {
|
export async function libraryGenerator(tree: Tree, schema: Schema) {
|
||||||
const options = normalizeOptions(tree, schema);
|
return await libraryGeneratorInternal(tree, {
|
||||||
|
projectNameAndRootFormat: 'derived',
|
||||||
|
...schema,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
|
const options = await normalizeOptions(tree, schema);
|
||||||
const tasks: GeneratorCallback[] = [
|
const tasks: GeneratorCallback[] = [
|
||||||
await initGenerator(tree, {
|
await initGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
@ -75,37 +78,42 @@ export async function libraryGenerator(tree: Tree, schema: Schema) {
|
|||||||
export default libraryGenerator;
|
export default libraryGenerator;
|
||||||
export const librarySchematic = convertNxGenerator(libraryGenerator);
|
export const librarySchematic = convertNxGenerator(libraryGenerator);
|
||||||
|
|
||||||
function normalizeOptions(tree: Tree, options: Schema): NormalizedSchema {
|
async function normalizeOptions(
|
||||||
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
tree: Tree,
|
||||||
options.directory
|
options: Schema
|
||||||
);
|
): Promise<NormalizedSchema> {
|
||||||
const { npmScope, libsDir: defaultLibsDir } = getWorkspaceLayout(tree);
|
const {
|
||||||
const libsDir = layoutDirectory ?? defaultLibsDir;
|
projectName,
|
||||||
const name = names(options.name).fileName;
|
names: projectNames,
|
||||||
const fullProjectDirectory = projectDirectory
|
projectRoot,
|
||||||
? `${names(projectDirectory).fileName}/${name}`
|
importPath,
|
||||||
: name;
|
projectNameAndRootFormat,
|
||||||
|
} = await determineProjectNameAndRootOptions(tree, {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'library',
|
||||||
|
directory: options.directory,
|
||||||
|
importPath: options.importPath,
|
||||||
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||||
|
callingGenerator: '@nx/node:library',
|
||||||
|
});
|
||||||
|
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||||
|
|
||||||
const projectName = fullProjectDirectory.replace(new RegExp('/', 'g'), '-');
|
|
||||||
const fileName = getCaseAwareFileName({
|
const fileName = getCaseAwareFileName({
|
||||||
fileName: options.simpleModuleName ? name : projectName,
|
fileName: options.simpleModuleName
|
||||||
|
? projectNames.projectSimpleName
|
||||||
|
: projectNames.projectFileName,
|
||||||
pascalCaseFiles: options.pascalCaseFiles,
|
pascalCaseFiles: options.pascalCaseFiles,
|
||||||
});
|
});
|
||||||
const projectRoot = joinPathFragments(libsDir, fullProjectDirectory);
|
|
||||||
|
|
||||||
const parsedTags = options.tags
|
const parsedTags = options.tags
|
||||||
? options.tags.split(',').map((s) => s.trim())
|
? options.tags.split(',').map((s) => s.trim())
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const importPath =
|
|
||||||
options.importPath || getImportPath(tree, fullProjectDirectory);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
fileName,
|
fileName,
|
||||||
name: projectName,
|
projectName,
|
||||||
projectRoot,
|
projectRoot,
|
||||||
projectDirectory: fullProjectDirectory,
|
|
||||||
parsedTags,
|
parsedTags,
|
||||||
importPath,
|
importPath,
|
||||||
};
|
};
|
||||||
@ -150,9 +158,7 @@ function updateProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const project = readProjectConfiguration(tree, options.name);
|
const project = readProjectConfiguration(tree, options.projectName);
|
||||||
const { libsDir } = getWorkspaceLayout(tree);
|
|
||||||
|
|
||||||
const rootProject = options.projectRoot === '.' || options.projectRoot === '';
|
const rootProject = options.projectRoot === '.' || options.projectRoot === '';
|
||||||
|
|
||||||
project.targets = project.targets || {};
|
project.targets = project.targets || {};
|
||||||
@ -162,9 +168,7 @@ function updateProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
options: {
|
options: {
|
||||||
outputPath: joinPathFragments(
|
outputPath: joinPathFragments(
|
||||||
'dist',
|
'dist',
|
||||||
rootProject
|
rootProject ? options.projectName : options.projectRoot
|
||||||
? options.projectDirectory
|
|
||||||
: `${libsDir}/${options.projectDirectory}`
|
|
||||||
),
|
),
|
||||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||||
packageJson: `${options.projectRoot}/package.json`,
|
packageJson: `${options.projectRoot}/package.json`,
|
||||||
@ -182,5 +186,5 @@ function updateProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
project.targets.build.options.srcRootForCompilationRoot = options.rootDir;
|
project.targets.build.options.srcRootForCompilationRoot = options.rootDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateProjectConfiguration(tree, options.name, project);
|
updateProjectConfiguration(tree, options.projectName, project);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
import { Linter } from '@nx/linter';
|
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
|
import type { Linter } from '@nx/linter';
|
||||||
|
|
||||||
export interface Schema {
|
export interface Schema {
|
||||||
name: string;
|
name: string;
|
||||||
directory?: string;
|
directory?: string;
|
||||||
|
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||||
simpleModuleName?: boolean;
|
simpleModuleName?: boolean;
|
||||||
skipTsConfig?: boolean;
|
skipTsConfig?: boolean;
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
|
|||||||
@ -19,13 +19,19 @@
|
|||||||
"$source": "argv",
|
"$source": "argv",
|
||||||
"index": 0
|
"index": 0
|
||||||
},
|
},
|
||||||
"x-prompt": "What name would you like to use for the library?"
|
"x-prompt": "What name would you like to use for the library?",
|
||||||
|
"pattern": "(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$"
|
||||||
},
|
},
|
||||||
"directory": {
|
"directory": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "A directory where the lib is placed",
|
"description": "A directory where the lib is placed",
|
||||||
"alias": "dir"
|
"alias": "dir"
|
||||||
},
|
},
|
||||||
|
"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"]
|
||||||
|
},
|
||||||
"simpleModuleName": {
|
"simpleModuleName": {
|
||||||
"description": "Keep the module name simple (when using `--directory`).",
|
"description": "Keep the module name simple (when using `--directory`).",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user