feat(angular): use helper to determine project name and root directory in project generators (#18607)
This commit is contained in:
parent
b9ca7ce09f
commit
47f8b7a8be
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "application",
|
||||
"factory": "./src/generators/application/application",
|
||||
"factory": "./src/generators/application/application#applicationGeneratorInternal",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "GeneratorNxApp",
|
||||
@ -14,13 +14,18 @@
|
||||
"type": "string",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What name would you like to use for the application?",
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"directory": {
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string",
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
@ -178,7 +183,7 @@
|
||||
"aliases": ["app"],
|
||||
"x-type": "application",
|
||||
"description": "Creates an Angular application.",
|
||||
"implementation": "/packages/angular/src/generators/application/application.ts",
|
||||
"implementation": "/packages/angular/src/generators/application/application#applicationGeneratorInternal.ts",
|
||||
"hidden": false,
|
||||
"path": "/packages/angular/src/generators/application/schema.json",
|
||||
"type": "generator"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "host",
|
||||
"factory": "./src/generators/host/host",
|
||||
"factory": "./src/generators/host/host#hostInternal",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "NxMFHost",
|
||||
@ -19,7 +19,7 @@
|
||||
"type": "string",
|
||||
"description": "The name to give to the host Angular application.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"remotes": {
|
||||
"type": "array",
|
||||
@ -35,6 +35,11 @@
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string"
|
||||
},
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
@ -173,7 +178,7 @@
|
||||
},
|
||||
"x-type": "application",
|
||||
"description": "Generate a Host Angular Module Federation Application.",
|
||||
"implementation": "/packages/angular/src/generators/host/host.ts",
|
||||
"implementation": "/packages/angular/src/generators/host/host#hostInternal.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/angular/src/generators/host/schema.json",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "library",
|
||||
"factory": "./src/generators/library/library",
|
||||
"factory": "./src/generators/library/library#libraryGeneratorInternal",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "GeneratorAngularLibrary",
|
||||
@ -14,13 +14,18 @@
|
||||
"description": "The name of the library.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-prompt": "What name would you like to use for the library?",
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"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 library is placed.",
|
||||
"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"]
|
||||
},
|
||||
"publishable": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
@ -205,7 +210,7 @@
|
||||
"aliases": ["lib"],
|
||||
"x-type": "library",
|
||||
"description": "Creates an Angular library.",
|
||||
"implementation": "/packages/angular/src/generators/library/library.ts",
|
||||
"implementation": "/packages/angular/src/generators/library/library#libraryGeneratorInternal.ts",
|
||||
"hidden": false,
|
||||
"path": "/packages/angular/src/generators/library/schema.json",
|
||||
"type": "generator"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "remote",
|
||||
"factory": "./src/generators/remote/remote",
|
||||
"factory": "./src/generators/remote/remote#remoteInternal",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "NxMFRemote",
|
||||
@ -19,7 +19,7 @@
|
||||
"type": "string",
|
||||
"description": "The name to give to the remote Angular app.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
@ -35,6 +35,11 @@
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string"
|
||||
},
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
@ -166,7 +171,7 @@
|
||||
},
|
||||
"x-type": "application",
|
||||
"description": "Generate a Remote Angular Module Federation Application.",
|
||||
"implementation": "/packages/angular/src/generators/remote/remote.ts",
|
||||
"implementation": "/packages/angular/src/generators/remote/remote#remoteInternal.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/angular/src/generators/remote/schema.json",
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { names } from '@nx/devkit';
|
||||
import {
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
killProcessAndPorts,
|
||||
newProject,
|
||||
@ -195,4 +196,39 @@ describe('Angular Module Federation', () => {
|
||||
// port and process cleanup
|
||||
await killProcessAndPorts(process.pid, hostPort, remote1Port, remote2Port);
|
||||
}, 20_000_000);
|
||||
|
||||
it('should should support generating host and remote apps with the new name and root format', async () => {
|
||||
const hostApp = uniq('host');
|
||||
const remoteApp = uniq('remote');
|
||||
const hostPort = 4800;
|
||||
const remotePort = 4801;
|
||||
|
||||
// generate host app
|
||||
runCLI(
|
||||
`generate @nx/angular:host ${hostApp} --project-name-and-root-format=as-provided --no-interactive`
|
||||
);
|
||||
// generate remote app
|
||||
runCLI(
|
||||
`generate @nx/angular:remote ${remoteApp} --host=${hostApp} --port=${remotePort} --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(`${hostApp}/src/app/app.module.ts`);
|
||||
checkFilesExist(`${remoteApp}/src/app/app.module.ts`);
|
||||
|
||||
// check default generated host is built successfully
|
||||
const buildOutput = runCLI(`build ${hostApp}`);
|
||||
expect(buildOutput).toContain('Successfully ran target build');
|
||||
|
||||
const process = await runCommandUntil(
|
||||
`serve ${hostApp} --port=${hostPort} --dev-remotes=${remoteApp}`,
|
||||
(output) =>
|
||||
output.includes(`listening on localhost:${remotePort}`) &&
|
||||
output.includes(`listening on localhost:${hostPort}`)
|
||||
);
|
||||
|
||||
// port and process cleanup
|
||||
await killProcessAndPorts(process.pid, hostPort, remotePort);
|
||||
}, 20_000_000);
|
||||
});
|
||||
|
||||
@ -350,4 +350,53 @@ describe('Angular Projects', () => {
|
||||
);
|
||||
expect(buildOutput).toContain('Successfully ran target build');
|
||||
});
|
||||
|
||||
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/angular: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/app/app.module.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/angular:lib ${libName} --buildable --project-name-and-root-format=derived`
|
||||
)
|
||||
).toThrow();
|
||||
|
||||
runCLI(
|
||||
`generate @nx/angular:lib ${libName} --buildable --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(
|
||||
`${libName}/src/index.ts`,
|
||||
`${libName}/src/lib/${libName.split('/')[1]}.module.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);
|
||||
});
|
||||
|
||||
@ -163,7 +163,7 @@
|
||||
"hidden": true
|
||||
},
|
||||
"application": {
|
||||
"factory": "./src/generators/application/application",
|
||||
"factory": "./src/generators/application/application#applicationGeneratorInternal",
|
||||
"schema": "./src/generators/application/schema.json",
|
||||
"aliases": ["app"],
|
||||
"x-type": "application",
|
||||
@ -211,7 +211,7 @@
|
||||
"hidden": true
|
||||
},
|
||||
"library": {
|
||||
"factory": "./src/generators/library/library",
|
||||
"factory": "./src/generators/library/library#libraryGeneratorInternal",
|
||||
"schema": "./src/generators/library/schema.json",
|
||||
"aliases": ["lib"],
|
||||
"x-type": "library",
|
||||
@ -224,7 +224,7 @@
|
||||
"description": "Creates a secondary entry point for an Angular publishable library."
|
||||
},
|
||||
"remote": {
|
||||
"factory": "./src/generators/remote/remote",
|
||||
"factory": "./src/generators/remote/remote#remoteInternal",
|
||||
"schema": "./src/generators/remote/schema.json",
|
||||
"x-type": "application",
|
||||
"description": "Generate a Remote Angular Module Federation Application."
|
||||
@ -241,7 +241,7 @@
|
||||
"description": "Converts an old micro frontend configuration to use the new withModuleFederation helper. It will run successfully if the following conditions are met: \n - Is either a host or remote application \n - Shared npm package configurations have not been modified \n - Name used to identify the Micro Frontend application matches the project name \n\n{% callout type=\"warning\" title=\"Overrides\" %}This generator will overwrite your webpack config. If you have additional custom configuration in your config file, it will be lost!{% /callout %}"
|
||||
},
|
||||
"host": {
|
||||
"factory": "./src/generators/host/host",
|
||||
"factory": "./src/generators/host/host#hostInternal",
|
||||
"schema": "./src/generators/host/schema.json",
|
||||
"x-type": "application",
|
||||
"description": "Generate a Host Angular Module Federation Application."
|
||||
|
||||
@ -30,6 +30,16 @@ import { prompt } from 'enquirer';
|
||||
export async function applicationGenerator(
|
||||
tree: Tree,
|
||||
schema: Partial<Schema>
|
||||
): Promise<GeneratorCallback> {
|
||||
return await applicationGeneratorInternal(tree, {
|
||||
projectNameAndRootFormat: 'derived',
|
||||
...schema,
|
||||
});
|
||||
}
|
||||
|
||||
export async function applicationGeneratorInternal(
|
||||
tree: Tree,
|
||||
schema: Partial<Schema>
|
||||
): Promise<GeneratorCallback> {
|
||||
const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree);
|
||||
|
||||
@ -50,7 +60,7 @@ export async function applicationGenerator(
|
||||
}).then((a) => a['standalone-components']);
|
||||
}
|
||||
|
||||
const options = normalizeOptions(tree, schema);
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
const rootOffset = offsetFromRoot(options.appProjectRoot);
|
||||
|
||||
await angularInitGenerator(tree, {
|
||||
|
||||
@ -10,19 +10,18 @@ import {
|
||||
} from '@nx/devkit';
|
||||
import { nxVersion } from '../../../utils/versions';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
import { removeScaffoldedE2e } from './remove-scaffolded-e2e';
|
||||
import { cypressProjectGenerator } from '@nx/cypress';
|
||||
|
||||
export async function addE2e(tree: Tree, options: NormalizedSchema) {
|
||||
removeScaffoldedE2e(tree, options, options.ngCliSchematicE2ERoot);
|
||||
|
||||
if (options.e2eTestRunner === 'cypress') {
|
||||
// TODO: This can call `@nx/web:static-config` generator when ready
|
||||
addFileServerTarget(tree, options, 'serve-static');
|
||||
|
||||
await cypressProjectGenerator(tree, {
|
||||
name: options.e2eProjectName,
|
||||
directory: options.directory,
|
||||
directory: options.e2eProjectRoot,
|
||||
// the name and root are already normalized, instruct the generator to use them as is
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
project: options.name,
|
||||
linter: options.linter,
|
||||
standaloneConfig: options.standaloneConfig,
|
||||
|
||||
@ -7,7 +7,5 @@ export * from './create-project';
|
||||
export * from './enable-strict-type-checking';
|
||||
export * from './normalize-options';
|
||||
export * from './normalized-schema';
|
||||
export * from './remove-scaffolded-e2e';
|
||||
export * from './set-app-strict-default';
|
||||
export * from './update-e2e-project';
|
||||
export * from './update-editor-tsconfig';
|
||||
|
||||
@ -1,45 +1,43 @@
|
||||
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 { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
|
||||
|
||||
import { Linter } from '@nx/linter';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
|
||||
import { normalizeNewProjectPrefix } from '../../utils/project';
|
||||
import type { Schema } from '../schema';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
|
||||
import { Linter } from '@nx/linter';
|
||||
import {
|
||||
normalizeDirectory,
|
||||
normalizeNewProjectPrefix,
|
||||
normalizeProjectName,
|
||||
} from '../../utils/project';
|
||||
|
||||
export function normalizeOptions(
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
options: Partial<Schema>
|
||||
): NormalizedSchema {
|
||||
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
||||
options.directory
|
||||
);
|
||||
const appDirectory = normalizeDirectory(options.name, projectDirectory);
|
||||
const appProjectName = normalizeProjectName(options.name, projectDirectory);
|
||||
const e2eProjectName = options.rootProject
|
||||
? 'e2e'
|
||||
: `${names(options.name).fileName}-e2e`;
|
||||
): Promise<NormalizedSchema> {
|
||||
const {
|
||||
projectName: appProjectName,
|
||||
projectRoot: appProjectRoot,
|
||||
projectNameAndRootFormat,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
options.rootProject = appProjectRoot === '.';
|
||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||
|
||||
const { appsDir: defaultAppsDir, standaloneAsDefault } =
|
||||
getWorkspaceLayout(host);
|
||||
const appsDir = layoutDirectory ?? defaultAppsDir;
|
||||
const appProjectRoot = options.rootProject
|
||||
? '.'
|
||||
: joinPathFragments(appsDir, appDirectory);
|
||||
const e2eProjectRoot = options.rootProject
|
||||
? 'e2e'
|
||||
: joinPathFragments(appsDir, `${appDirectory}-e2e`);
|
||||
let e2eProjectName = 'e2e';
|
||||
let e2eProjectRoot = 'e2e';
|
||||
if (!options.rootProject) {
|
||||
const projectNameAndRoot = await determineProjectNameAndRootOptions(host, {
|
||||
name: `${options.name}-e2e`,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
e2eProjectName = projectNameAndRoot.projectName;
|
||||
e2eProjectRoot = projectNameAndRoot.projectRoot;
|
||||
}
|
||||
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
@ -51,11 +49,6 @@ export function normalizeOptions(
|
||||
'app'
|
||||
);
|
||||
|
||||
options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault;
|
||||
|
||||
const ngCliSchematicAppRoot = appProjectName;
|
||||
const ngCliSchematicE2ERoot = `${appProjectName}/e2e`;
|
||||
|
||||
// Set defaults and then overwrite with user options
|
||||
return {
|
||||
style: 'css',
|
||||
@ -76,7 +69,5 @@ export function normalizeOptions(
|
||||
e2eProjectRoot,
|
||||
e2eProjectName,
|
||||
parsedTags,
|
||||
ngCliSchematicAppRoot,
|
||||
ngCliSchematicE2ERoot,
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,6 +11,4 @@ export interface NormalizedSchema extends Schema {
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
ngCliSchematicAppRoot: string;
|
||||
ngCliSchematicE2ERoot: string;
|
||||
}
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
import {
|
||||
updateProjectConfiguration,
|
||||
readProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
|
||||
export function removeScaffoldedE2e(
|
||||
host: Tree,
|
||||
{ name }: NormalizedSchema,
|
||||
e2eProjectRoot: string
|
||||
) {
|
||||
if (host.exists(`${e2eProjectRoot}/src/app.e2e-spec.ts`)) {
|
||||
host.delete(`${e2eProjectRoot}/src/app.e2e-spec.ts`);
|
||||
}
|
||||
if (host.exists(`${e2eProjectRoot}/src/app.po.ts`)) {
|
||||
host.delete(`${e2eProjectRoot}/src/app.po.ts`);
|
||||
}
|
||||
if (host.exists(`${e2eProjectRoot}/protractor.conf.js`)) {
|
||||
host.delete(`${e2eProjectRoot}/protractor.conf.js`);
|
||||
}
|
||||
if (host.exists(`${e2eProjectRoot}/tsconfig.json`)) {
|
||||
host.delete(`${e2eProjectRoot}/tsconfig.json`);
|
||||
}
|
||||
|
||||
const project = readProjectConfiguration(host, name);
|
||||
delete project.targets['e2e'];
|
||||
|
||||
updateProjectConfiguration(host, name, project);
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
import type { ProjectConfiguration, Tree } from '@nx/devkit';
|
||||
import {
|
||||
addProjectConfiguration,
|
||||
offsetFromRoot,
|
||||
readProjectConfiguration,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { getRelativePathToRootTsConfig } from '@nx/js';
|
||||
import type { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
export function updateE2eProject(tree: Tree, options: NormalizedSchema) {
|
||||
const spec = `${options.e2eProjectRoot}/src/app.e2e-spec.ts`;
|
||||
const content = tree.read(spec, 'utf-8');
|
||||
tree.write(
|
||||
spec,
|
||||
content.replace(
|
||||
`${options.name} app is running!`,
|
||||
`Welcome ${options.name}`
|
||||
)
|
||||
);
|
||||
|
||||
const page = `${options.e2eProjectRoot}/src/app.po.ts`;
|
||||
const pageContent = tree.read(page, 'utf-8');
|
||||
tree.write(page, pageContent.replace(`.content span`, `header h1`));
|
||||
|
||||
const proj = readProjectConfiguration(tree, options.name);
|
||||
const project: ProjectConfiguration = {
|
||||
root: options.e2eProjectRoot,
|
||||
projectType: 'application',
|
||||
targets: {
|
||||
e2e: proj.targets.e2e,
|
||||
},
|
||||
implicitDependencies: [options.name],
|
||||
tags: [],
|
||||
};
|
||||
project.targets.e2e.options.protractorConfig = `${options.e2eProjectRoot}/protractor.conf.js`;
|
||||
addProjectConfiguration(tree, options.e2eProjectName, project);
|
||||
|
||||
delete proj.targets.e2e;
|
||||
updateProjectConfiguration(tree, options.name, proj);
|
||||
|
||||
// update tsconfig e2e
|
||||
if (!tree.exists(`${options.e2eProjectRoot}/tsconfig.e2e.json`)) {
|
||||
tree.write(`${options.e2eProjectRoot}/tsconfig.e2e.json`, '{}');
|
||||
}
|
||||
|
||||
updateJson(tree, `${options.e2eProjectRoot}/tsconfig.e2e.json`, (json) => {
|
||||
return {
|
||||
...json,
|
||||
extends: `./tsconfig.json`,
|
||||
compilerOptions: {
|
||||
...json.compilerOptions,
|
||||
outDir: `${offsetFromRoot(options.e2eProjectRoot)}dist/out-tsc`,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// update tsconfig
|
||||
updateJson(tree, `${options.e2eProjectRoot}/tsconfig.json`, (json) => {
|
||||
return {
|
||||
...json,
|
||||
extends: getRelativePathToRootTsConfig(tree, options.e2eProjectRoot),
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
import { Linter } from '@nx/linter';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { Linter } from '@nx/linter';
|
||||
import type { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { Styles } from '../utils/types';
|
||||
|
||||
export interface Schema {
|
||||
@ -14,6 +15,7 @@ export interface Schema {
|
||||
style?: Styles;
|
||||
skipTests?: boolean;
|
||||
directory?: string;
|
||||
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||
tags?: string;
|
||||
linter?: Linter;
|
||||
unitTestRunner?: UnitTestRunner;
|
||||
|
||||
@ -14,13 +14,18 @@
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use for the application?",
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"directory": {
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string",
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
|
||||
@ -1,23 +1,28 @@
|
||||
import {
|
||||
extractLayoutDirectory,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
runTasksInSerial,
|
||||
stripIndents,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import type { Schema } from './schema';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { lt } from 'semver';
|
||||
import { E2eTestRunner } from '../../utils/test-runners';
|
||||
import applicationGenerator from '../application/application';
|
||||
import remoteGenerator from '../remote/remote';
|
||||
import { normalizeProjectName } from '../utils/project';
|
||||
import { setupMf } from '../setup-mf/setup-mf';
|
||||
import { E2eTestRunner } from '../../utils/test-runners';
|
||||
import { addSsr } from './lib';
|
||||
|
||||
import { getInstalledAngularVersionInfo } from '../utils/version-utils';
|
||||
import { lt } from 'semver';
|
||||
import { addSsr } from './lib';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
export async function host(tree: Tree, options: Schema) {
|
||||
return await hostInternal(tree, {
|
||||
projectNameAndRootFormat: 'derived',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export async function hostInternal(tree: Tree, options: Schema) {
|
||||
const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree);
|
||||
|
||||
if (lt(installedAngularVersionInfo.version, '14.1.0') && options.standalone) {
|
||||
@ -40,8 +45,14 @@ export async function host(tree: Tree, options: Schema) {
|
||||
});
|
||||
}
|
||||
|
||||
const { projectDirectory } = extractLayoutDirectory(options.directory);
|
||||
const appName = normalizeProjectName(options.name, projectDirectory);
|
||||
const { projectName: hostProjectName, projectNameAndRootFormat } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||
});
|
||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||
|
||||
const appInstallTask = await applicationGenerator(tree, {
|
||||
...options,
|
||||
@ -54,7 +65,7 @@ export async function host(tree: Tree, options: Schema) {
|
||||
const skipE2E =
|
||||
!options.e2eTestRunner || options.e2eTestRunner === E2eTestRunner.None;
|
||||
await setupMf(tree, {
|
||||
appName,
|
||||
appName: hostProjectName,
|
||||
mfType: 'host',
|
||||
routing: true,
|
||||
port: 4200,
|
||||
@ -63,13 +74,13 @@ export async function host(tree: Tree, options: Schema) {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
skipE2E,
|
||||
e2eProjectName: skipE2E ? undefined : `${appName}-e2e`,
|
||||
e2eProjectName: skipE2E ? undefined : `${hostProjectName}-e2e`,
|
||||
prefix: options.prefix,
|
||||
});
|
||||
|
||||
let installTasks = [appInstallTask];
|
||||
if (options.ssr) {
|
||||
let ssrInstallTask = await addSsr(tree, options, appName);
|
||||
let ssrInstallTask = await addSsr(tree, options, hostProjectName);
|
||||
installTasks.push(ssrInstallTask);
|
||||
}
|
||||
|
||||
@ -77,7 +88,7 @@ export async function host(tree: Tree, options: Schema) {
|
||||
await remoteGenerator(tree, {
|
||||
...options,
|
||||
name: remote,
|
||||
host: appName,
|
||||
host: hostProjectName,
|
||||
skipFormat: true,
|
||||
standalone: options.standalone,
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Linter } from '@nx/linter';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { Linter } from '@nx/linter';
|
||||
import type { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { Styles } from '../utils/types';
|
||||
|
||||
export interface Schema {
|
||||
@ -14,6 +15,7 @@ export interface Schema {
|
||||
style?: Styles;
|
||||
skipTests?: boolean;
|
||||
directory?: string;
|
||||
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||
tags?: string;
|
||||
linter?: Linter;
|
||||
unitTestRunner?: UnitTestRunner;
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"remotes": {
|
||||
"type": "array",
|
||||
@ -35,6 +35,11 @@
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string"
|
||||
},
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
|
||||
@ -1,22 +1,16 @@
|
||||
import {
|
||||
extractLayoutDirectory,
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
names,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { names, Tree } from '@nx/devkit';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
|
||||
|
||||
import { Linter } from '@nx/linter';
|
||||
|
||||
import { Schema } from '../schema';
|
||||
import { NormalizedSchema } from './normalized-schema';
|
||||
import { UnitTestRunner } from '../../../utils/test-runners';
|
||||
import { normalizeNewProjectPrefix } from '../../utils/project';
|
||||
import { Schema } from '../schema';
|
||||
import { NormalizedSchema } from './normalized-schema';
|
||||
|
||||
export function normalizeOptions(host: Tree, schema: Schema): NormalizedSchema {
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
schema: Schema
|
||||
): Promise<NormalizedSchema> {
|
||||
// Create a schema with populated default values
|
||||
const options: Schema = {
|
||||
buildable: false,
|
||||
@ -33,37 +27,32 @@ export function normalizeOptions(host: Tree, schema: Schema): NormalizedSchema {
|
||||
...schema,
|
||||
};
|
||||
|
||||
const name = names(options.name).fileName;
|
||||
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(
|
||||
options.directory
|
||||
);
|
||||
const fullProjectDirectory = projectDirectory
|
||||
? `${names(projectDirectory).fileName}/${name}`.replace(/\/+/g, '/')
|
||||
: name;
|
||||
const {
|
||||
projectName,
|
||||
names: projectNames,
|
||||
projectRoot,
|
||||
importPath,
|
||||
} = await determineProjectNameAndRootOptions(host, {
|
||||
name: options.name,
|
||||
projectType: 'library',
|
||||
directory: options.directory,
|
||||
importPath: options.importPath,
|
||||
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||
});
|
||||
|
||||
const { libsDir: defaultLibsDirectory, standaloneAsDefault } =
|
||||
getWorkspaceLayout(host);
|
||||
const npmScope = getNpmScope(host);
|
||||
const libsDir = layoutDirectory ?? defaultLibsDirectory;
|
||||
|
||||
const projectName = fullProjectDirectory
|
||||
.replace(new RegExp('/', 'g'), '-')
|
||||
.replace(/-\d+/g, '');
|
||||
const fileName = options.simpleName ? name : projectName;
|
||||
const projectRoot = joinPathFragments(libsDir, fullProjectDirectory);
|
||||
const fileName = options.simpleName
|
||||
? projectNames.projectSimpleName
|
||||
: projectNames.projectFileName;
|
||||
|
||||
const moduleName = `${names(fileName).className}Module`;
|
||||
const parsedTags = options.tags
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
const modulePath = `${projectRoot}/src/lib/${fileName}.module.ts`;
|
||||
|
||||
const npmScope = getNpmScope(host);
|
||||
const prefix = normalizeNewProjectPrefix(options.prefix, npmScope, 'lib');
|
||||
|
||||
options.standaloneConfig = options.standaloneConfig ?? standaloneAsDefault;
|
||||
|
||||
const importPath =
|
||||
options.importPath || getImportPath(host, fullProjectDirectory);
|
||||
|
||||
const ngCliSchematicLibRoot = projectName;
|
||||
const allNormalizedOptions = {
|
||||
...options,
|
||||
@ -74,13 +63,14 @@ export function normalizeOptions(host: Tree, schema: Schema): NormalizedSchema {
|
||||
projectRoot,
|
||||
entryFile: 'index',
|
||||
moduleName,
|
||||
projectDirectory: fullProjectDirectory,
|
||||
modulePath,
|
||||
parsedTags,
|
||||
fileName,
|
||||
importPath,
|
||||
ngCliSchematicLibRoot,
|
||||
standaloneComponentName: `${names(name).className}Component`,
|
||||
standaloneComponentName: `${
|
||||
names(projectNames.projectSimpleName).className
|
||||
}Component`,
|
||||
};
|
||||
|
||||
const {
|
||||
|
||||
@ -35,7 +35,6 @@ export interface NormalizedSchema {
|
||||
entryFile: string;
|
||||
modulePath: string;
|
||||
moduleName: string;
|
||||
projectDirectory: string;
|
||||
parsedTags: string[];
|
||||
ngCliSchematicLibRoot: string;
|
||||
standaloneComponentName: string;
|
||||
|
||||
@ -571,7 +571,7 @@ describe('lib', () => {
|
||||
it('should accept numbers in the path', async () => {
|
||||
await runLibraryGeneratorWithOpts({ directory: 'src/1-api' });
|
||||
|
||||
expect(readProjectConfiguration(tree, 'src-api-my-lib').root).toEqual(
|
||||
expect(readProjectConfiguration(tree, 'src-1-api-my-lib').root).toEqual(
|
||||
'src/1-api/my-lib'
|
||||
);
|
||||
});
|
||||
|
||||
@ -36,6 +36,18 @@ import { addProject } from './lib/add-project';
|
||||
export async function libraryGenerator(
|
||||
tree: Tree,
|
||||
schema: Schema
|
||||
): Promise<GeneratorCallback> {
|
||||
return await libraryGeneratorInternal(tree, {
|
||||
// provide a default projectNameAndRootFormat to avoid breaking changes
|
||||
// to external generators invoking this one
|
||||
projectNameAndRootFormat: 'derived',
|
||||
...schema,
|
||||
});
|
||||
}
|
||||
|
||||
export async function libraryGeneratorInternal(
|
||||
tree: Tree,
|
||||
schema: Schema
|
||||
): Promise<GeneratorCallback> {
|
||||
// Do some validation checks
|
||||
if (!schema.routing && schema.lazy) {
|
||||
@ -61,7 +73,7 @@ export async function libraryGenerator(
|
||||
);
|
||||
}
|
||||
|
||||
const options = normalizeOptions(tree, schema);
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
const { libraryOptions } = options;
|
||||
|
||||
const pkgVersions = versions(tree);
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { UnitTestRunner } from '../../utils/test-runners';
|
||||
import { Linter } from '@nx/linter';
|
||||
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-directory-utils';
|
||||
import type { Linter } from '@nx/linter';
|
||||
import type { UnitTestRunner } from '../../utils/test-runners';
|
||||
|
||||
export interface Schema {
|
||||
name: string;
|
||||
@ -8,6 +9,7 @@ export interface Schema {
|
||||
simpleName?: boolean;
|
||||
addModuleSpec?: boolean;
|
||||
directory?: string;
|
||||
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||
sourceDir?: string;
|
||||
buildable?: boolean;
|
||||
publishable?: boolean;
|
||||
|
||||
@ -14,13 +14,18 @@
|
||||
"index": 0
|
||||
},
|
||||
"x-prompt": "What name would you like to use for the library?",
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"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 library is placed.",
|
||||
"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"]
|
||||
},
|
||||
"publishable": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@ -1,22 +1,27 @@
|
||||
import {
|
||||
extractLayoutDirectory,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
runTasksInSerial,
|
||||
stripIndents,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import type { Schema } from './schema';
|
||||
import applicationGenerator from '../application/application';
|
||||
import { normalizeProjectName } from '../utils/project';
|
||||
import { setupMf } from '../setup-mf/setup-mf';
|
||||
import { E2eTestRunner } from '../../utils/test-runners';
|
||||
import { addSsr, findNextAvailablePort } from './lib';
|
||||
|
||||
import { getInstalledAngularVersionInfo } from '../utils/version-utils';
|
||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { lt } from 'semver';
|
||||
import { E2eTestRunner } from '../../utils/test-runners';
|
||||
import { applicationGenerator } from '../application/application';
|
||||
import { setupMf } from '../setup-mf/setup-mf';
|
||||
import { getInstalledAngularVersionInfo } from '../utils/version-utils';
|
||||
import { addSsr, findNextAvailablePort } from './lib';
|
||||
import type { Schema } from './schema';
|
||||
|
||||
export async function remote(tree: Tree, options: Schema) {
|
||||
return await remoteInternal(tree, {
|
||||
projectNameAndRootFormat: 'derived',
|
||||
...options,
|
||||
});
|
||||
}
|
||||
|
||||
export async function remoteInternal(tree: Tree, options: Schema) {
|
||||
const installedAngularVersionInfo = getInstalledAngularVersionInfo(tree);
|
||||
|
||||
if (lt(installedAngularVersionInfo.version, '14.1.0') && options.standalone) {
|
||||
@ -31,8 +36,15 @@ export async function remote(tree: Tree, options: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
const { projectDirectory } = extractLayoutDirectory(options.directory);
|
||||
const appName = normalizeProjectName(options.name, projectDirectory);
|
||||
const { projectName: remoteProjectName, projectNameAndRootFormat } =
|
||||
await determineProjectNameAndRootOptions(tree, {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
directory: options.directory,
|
||||
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
||||
});
|
||||
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
||||
|
||||
const port = options.port ?? findNextAvailablePort(tree);
|
||||
|
||||
const appInstallTask = await applicationGenerator(tree, {
|
||||
@ -47,7 +59,7 @@ export async function remote(tree: Tree, options: Schema) {
|
||||
!options.e2eTestRunner || options.e2eTestRunner === E2eTestRunner.None;
|
||||
|
||||
await setupMf(tree, {
|
||||
appName,
|
||||
appName: remoteProjectName,
|
||||
mfType: 'remote',
|
||||
routing: true,
|
||||
host: options.host,
|
||||
@ -55,7 +67,7 @@ export async function remote(tree: Tree, options: Schema) {
|
||||
skipPackageJson: options.skipPackageJson,
|
||||
skipFormat: true,
|
||||
skipE2E,
|
||||
e2eProjectName: skipE2E ? undefined : `${appName}-e2e`,
|
||||
e2eProjectName: skipE2E ? undefined : `${remoteProjectName}-e2e`,
|
||||
standalone: options.standalone,
|
||||
prefix: options.prefix,
|
||||
});
|
||||
@ -63,7 +75,7 @@ export async function remote(tree: Tree, options: Schema) {
|
||||
let installTasks = [appInstallTask];
|
||||
if (options.ssr) {
|
||||
let ssrInstallTask = await addSsr(tree, {
|
||||
appName,
|
||||
appName: remoteProjectName,
|
||||
port,
|
||||
standalone: options.standalone,
|
||||
});
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { Linter } from '@nx/linter';
|
||||
import { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { Linter } from '@nx/linter';
|
||||
import type { E2eTestRunner, UnitTestRunner } from '../../utils/test-runners';
|
||||
import type { Styles } from '../utils/types';
|
||||
|
||||
export interface Schema {
|
||||
@ -13,6 +14,7 @@ export interface Schema {
|
||||
style?: Styles;
|
||||
skipTests?: boolean;
|
||||
directory?: string;
|
||||
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
||||
tags?: string;
|
||||
linter?: Linter;
|
||||
unitTestRunner?: UnitTestRunner;
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"pattern": "^[a-zA-Z].*$"
|
||||
"pattern": "^[a-zA-Z][^:]*$"
|
||||
},
|
||||
"host": {
|
||||
"type": "string",
|
||||
@ -35,6 +35,11 @@
|
||||
"description": "The directory of the new application.",
|
||||
"type": "string"
|
||||
},
|
||||
"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"]
|
||||
},
|
||||
"style": {
|
||||
"description": "The file extension to be used for style files.",
|
||||
"type": "string",
|
||||
|
||||
@ -50,6 +50,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@proj/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -69,6 +70,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -89,6 +91,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@custom-scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -111,6 +114,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: '@scope/lib-name',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -135,6 +139,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: 'lib-name',
|
||||
projectRoot: '.',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -181,6 +186,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@proj/shared/lib-name',
|
||||
projectRoot: 'shared/lib-name',
|
||||
projectNameAndRootFormat: 'derived',
|
||||
});
|
||||
});
|
||||
|
||||
@ -215,6 +221,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: 'lib-name',
|
||||
projectRoot: '.',
|
||||
projectNameAndRootFormat: 'derived',
|
||||
});
|
||||
});
|
||||
|
||||
@ -288,6 +295,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
// restore original interactive mode
|
||||
@ -317,6 +325,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@proj/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -336,6 +345,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -356,6 +366,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@custom-scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -379,6 +390,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: '@scope/lib-name',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -403,6 +415,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: 'lib-name',
|
||||
projectRoot: '.',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
});
|
||||
|
||||
@ -449,6 +462,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@proj/shared/lib-name',
|
||||
projectRoot: 'libs/shared/lib-name',
|
||||
projectNameAndRootFormat: 'derived',
|
||||
});
|
||||
});
|
||||
|
||||
@ -484,6 +498,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: 'lib-name',
|
||||
projectRoot: '.',
|
||||
projectNameAndRootFormat: 'derived',
|
||||
});
|
||||
});
|
||||
|
||||
@ -557,6 +572,7 @@ describe('determineProjectNameAndRootOptions', () => {
|
||||
},
|
||||
importPath: '@scope/lib-name',
|
||||
projectRoot: 'shared',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
// restore original interactive mode
|
||||
|
||||
@ -57,13 +57,20 @@ type ProjectNameAndRootFormats = {
|
||||
export async function determineProjectNameAndRootOptions(
|
||||
tree: Tree,
|
||||
options: ProjectGenerationOptions
|
||||
): Promise<ProjectNameAndRootOptions> {
|
||||
): Promise<
|
||||
ProjectNameAndRootOptions & {
|
||||
projectNameAndRootFormat: ProjectNameAndRootFormat;
|
||||
}
|
||||
> {
|
||||
validateName(options.name, options.projectNameAndRootFormat);
|
||||
const formats = getProjectNameAndRootFormats(tree, options);
|
||||
const format =
|
||||
options.projectNameAndRootFormat ?? (await determineFormat(formats));
|
||||
|
||||
return formats[format];
|
||||
return {
|
||||
...formats[format],
|
||||
projectNameAndRootFormat: format,
|
||||
};
|
||||
}
|
||||
|
||||
function validateName(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user