diff --git a/docs/generated/cli/create-nx-workspace.md b/docs/generated/cli/create-nx-workspace.md
index ac1210df32eaaf..b9d0be745f0964 100644
--- a/docs/generated/cli/create-nx-workspace.md
+++ b/docs/generated/cli/create-nx-workspace.md
@@ -135,6 +135,12 @@ Default: `npm`
Package manager to use
+### prefix
+
+Type: `boolean`
+
+Prefix to use for Angular component and directive selectors.
+
### preset
Type: `string`
diff --git a/docs/generated/packages/angular/generators/application.json b/docs/generated/packages/angular/generators/application.json
index 2cfad4c3b36c2e..6123da361f8977 100644
--- a/docs/generated/packages/angular/generators/application.json
+++ b/docs/generated/packages/angular/generators/application.json
@@ -78,6 +78,7 @@
"type": "string",
"format": "html-selector",
"description": "The prefix to apply to generated selectors.",
+ "default": "app",
"alias": "p"
},
"skipTests": {
diff --git a/docs/generated/packages/nx/documents/create-nx-workspace.md b/docs/generated/packages/nx/documents/create-nx-workspace.md
index ac1210df32eaaf..b9d0be745f0964 100644
--- a/docs/generated/packages/nx/documents/create-nx-workspace.md
+++ b/docs/generated/packages/nx/documents/create-nx-workspace.md
@@ -135,6 +135,12 @@ Default: `npm`
Package manager to use
+### prefix
+
+Type: `boolean`
+
+Prefix to use for Angular component and directive selectors.
+
### preset
Type: `string`
diff --git a/docs/generated/packages/workspace/generators/new.json b/docs/generated/packages/workspace/generators/new.json
index f1d31c68b83bf0..c0e68a442b7250 100644
--- a/docs/generated/packages/workspace/generators/new.json
+++ b/docs/generated/packages/workspace/generators/new.json
@@ -79,6 +79,10 @@
"description": "Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application.",
"type": "boolean",
"default": false
+ },
+ "prefix": {
+ "description": "The prefix to use for Angular component and directive selectors.",
+ "type": "string"
}
},
"additionalProperties": true,
diff --git a/docs/generated/packages/workspace/generators/preset.json b/docs/generated/packages/workspace/generators/preset.json
index a04f2482976eb1..9b050e4602033c 100644
--- a/docs/generated/packages/workspace/generators/preset.json
+++ b/docs/generated/packages/workspace/generators/preset.json
@@ -96,6 +96,10 @@
"description": "Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application.",
"type": "boolean",
"default": false
+ },
+ "prefix": {
+ "description": "The prefix to use for Angular component and directive selectors.",
+ "type": "string"
}
},
"required": ["preset", "name"],
diff --git a/e2e/angular-module-federation/src/module-federation.test.ts b/e2e/angular-module-federation/src/module-federation.test.ts
index 52b6b6dbe05c42..9bed894dd45d20 100644
--- a/e2e/angular-module-federation/src/module-federation.test.ts
+++ b/e2e/angular-module-federation/src/module-federation.test.ts
@@ -345,7 +345,7 @@ describe('Angular Module Federation', () => {
import { isEven } from '${remote}/${module}';
@Component({
- selector: 'proj-root',
+ selector: 'app-root',
template: \`
{{title}}
\`,
standalone: true
})
@@ -420,7 +420,7 @@ describe('Angular Module Federation', () => {
import { isEven } from '${childRemote}/${module}';
@Component({
- selector: 'proj-${remote}-entry',
+ selector: 'app-${remote}-entry',
template: \`{{title}}
\`,
standalone: true
})
diff --git a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap
index 072f5e11f8e213..6fd1e52c72f17a 100644
--- a/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap
+++ b/packages/angular/src/generators/application/__snapshots__/application.spec.ts.snap
@@ -24,7 +24,7 @@ exports[`app --minimal should skip "nx-welcome.component.ts" file and references
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -83,7 +83,7 @@ exports[`app --minimal should skip "nx-welcome.component.ts" file and references
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -127,7 +127,7 @@ import { RouterModule } from '@angular/router';
@Component({
standalone: true,
imports: [RouterModule],
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -170,7 +170,7 @@ exports[`app --minimal should skip "nx-welcome.component.ts" file and references
@Component({
standalone: true,
imports: [],
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -210,7 +210,7 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh
{
"$schema": "../../../node_modules/nx/schemas/project-schema.json",
"name": "my-dir-my-app",
- "prefix": "proj",
+ "prefix": "app",
"projectType": "application",
"root": "apps/my-dir/my-app",
"sourceRoot": "apps/my-dir/my-app/src",
@@ -429,7 +429,7 @@ exports[`app --project-name-and-root-format=derived should generate correctly wh
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "my-app",
- "prefix": "proj",
+ "prefix": "app",
"projectType": "application",
"root": "apps/my-app",
"sourceRoot": "apps/my-app/src",
@@ -681,7 +681,7 @@ import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [NxWelcomeComponent, RouterModule],
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -749,7 +749,7 @@ import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [NxWelcomeComponent, ],
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -890,7 +890,7 @@ exports[`app format files should format files 2`] = `
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
@@ -943,7 +943,7 @@ exports[`app nested should create project configs 1`] = `
{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "my-app",
- "prefix": "proj",
+ "prefix": "app",
"projectType": "application",
"root": "my-dir/my-app",
"sourceRoot": "my-dir/my-app/src",
@@ -1075,7 +1075,7 @@ exports[`app not nested should create project configs 1`] = `
{
"$schema": "../node_modules/nx/schemas/project-schema.json",
"name": "my-app",
- "prefix": "proj",
+ "prefix": "app",
"projectType": "application",
"root": "my-app",
"sourceRoot": "my-app/src",
diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts
index 65304ca4e35006..78865d8108d1c2 100644
--- a/packages/angular/src/generators/application/application.spec.ts
+++ b/packages/angular/src/generators/application/application.spec.ts
@@ -450,7 +450,7 @@ describe('app', () => {
await generateApp(appTree, 'my-app', { directory: 'my-dir/my-app' });
expect(
appTree.read('my-dir/my-app/src/app/app.component.html', 'utf-8')
- ).toContain('');
+ ).toContain('');
});
it("should update `template`'s property of AppComponent with Nx content", async () => {
@@ -460,7 +460,7 @@ describe('app', () => {
});
expect(
appTree.read('my-dir/my-app/src/app/app.component.ts', 'utf-8')
- ).toContain('');
+ ).toContain('');
});
it('should create Nx specific `nx-welcome.component.ts` file', async () => {
@@ -571,7 +571,7 @@ describe('app', () => {
"@angular-eslint/component-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "app",
"style": "kebab-case",
"type": "element",
},
@@ -579,7 +579,7 @@ describe('app', () => {
"@angular-eslint/directive-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "app",
"style": "camelCase",
"type": "attribute",
},
diff --git a/packages/angular/src/generators/application/lib/create-files.ts b/packages/angular/src/generators/application/lib/create-files.ts
index 8bc45d738179a5..2777ba0259d0fe 100644
--- a/packages/angular/src/generators/application/lib/create-files.ts
+++ b/packages/angular/src/generators/application/lib/create-files.ts
@@ -5,6 +5,7 @@ import { getRelativePathToRootTsConfig, getRootTsConfigFileName } from '@nx/js';
import { createTsConfig } from '../../utils/create-ts-config';
import { UnitTestRunner } from '../../../utils/test-runners';
import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
+import { validateHtmlSelector } from '../../utils/selector';
export async function createFiles(
tree: Tree,
@@ -15,8 +16,13 @@ export async function createFiles(
const isUsingApplicationBuilder =
angularMajorVersion >= 17 && options.bundler === 'esbuild';
+ const rootSelector = `${options.prefix}-root`;
+ validateHtmlSelector(rootSelector);
+ const nxWelcomeSelector = `${options.prefix}-nx-welcome`;
+ validateHtmlSelector(nxWelcomeSelector);
+
const substitutions = {
- rootSelector: `${options.prefix}-root`,
+ rootSelector,
appName: options.name,
inlineStyle: options.inlineStyle,
inlineTemplate: options.inlineTemplate,
@@ -25,7 +31,7 @@ export async function createFiles(
unitTesting: options.unitTestRunner !== UnitTestRunner.None,
routing: options.routing,
minimal: options.minimal,
- nxWelcomeSelector: `${options.prefix}-nx-welcome`,
+ nxWelcomeSelector,
rootTsConfig: joinPathFragments(rootOffset, getRootTsConfigFileName(tree)),
angularMajorVersion,
rootOffset,
diff --git a/packages/angular/src/generators/application/lib/normalize-options.ts b/packages/angular/src/generators/application/lib/normalize-options.ts
index c86e4d2043b226..43ff39c8c55328 100644
--- a/packages/angular/src/generators/application/lib/normalize-options.ts
+++ b/packages/angular/src/generators/application/lib/normalize-options.ts
@@ -1,9 +1,7 @@
import { joinPathFragments, type Tree } from '@nx/devkit';
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
import { Linter } from '@nx/eslint';
-import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
import { E2eTestRunner, UnitTestRunner } from '../../../utils/test-runners';
-import { normalizeNewProjectPrefix } from '../../utils/project';
import type { Schema } from '../schema';
import type { NormalizedSchema } from './normalized-schema';
import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
@@ -35,12 +33,6 @@ export async function normalizeOptions(
? options.tags.split(',').map((s) => s.trim())
: [];
- const prefix = normalizeNewProjectPrefix(
- options.prefix,
- getNpmScope(host),
- 'app'
- );
-
let bundler = options.bundler;
if (!bundler) {
const { major: angularMajorVersion } = getInstalledAngularVersionInfo(host);
@@ -61,7 +53,7 @@ export async function normalizeOptions(
strict: true,
standalone: true,
...options,
- prefix,
+ prefix: options.prefix || 'app',
name: appProjectName,
appProjectRoot,
appProjectSourceRoot: `${appProjectRoot}/src`,
diff --git a/packages/angular/src/generators/application/schema.json b/packages/angular/src/generators/application/schema.json
index daf56df4bd41c6..3b915e47857fc8 100644
--- a/packages/angular/src/generators/application/schema.json
+++ b/packages/angular/src/generators/application/schema.json
@@ -81,6 +81,7 @@
"type": "string",
"format": "html-selector",
"description": "The prefix to apply to generated selectors.",
+ "default": "app",
"alias": "p"
},
"skipTests": {
diff --git a/packages/angular/src/generators/component/__snapshots__/component.spec.ts.snap b/packages/angular/src/generators/component/__snapshots__/component.spec.ts.snap
index 11bf85802ec837..d082b8eae44182 100644
--- a/packages/angular/src/generators/component/__snapshots__/component.spec.ts.snap
+++ b/packages/angular/src/generators/component/__snapshots__/component.spec.ts.snap
@@ -4,7 +4,7 @@ exports[`component Generator --flat should create the component correctly and ex
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -16,7 +16,7 @@ exports[`component Generator --flat should create the component correctly and no
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -41,7 +41,7 @@ exports[`component Generator --path should create the component correctly and ex
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -53,7 +53,7 @@ exports[`component Generator compat should inline styles when --inline-style=tru
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styles: \`\`
})
@@ -65,7 +65,7 @@ exports[`component Generator secondary entry points should create the component
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -82,7 +82,7 @@ exports[`component Generator should create component files correctly: component
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css',
})
@@ -131,7 +131,7 @@ exports[`component Generator should create the component correctly and export it
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -149,7 +149,7 @@ exports[`component Generator should create the component correctly and export it
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
standalone: true,
imports: [CommonModule],
templateUrl: './example.component.html',
@@ -163,7 +163,7 @@ exports[`component Generator should create the component correctly and not expor
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -176,7 +176,7 @@ exports[`component Generator should create the component correctly and not expor
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
standalone: true,
imports: [CommonModule],
templateUrl: './example.component.html',
@@ -190,7 +190,7 @@ exports[`component Generator should create the component correctly and not expor
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -202,7 +202,7 @@ exports[`component Generator should create the component correctly but not expor
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -214,7 +214,7 @@ exports[`component Generator should inline styles when --inline-style=true 1`] =
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styles: \`\`
})
@@ -226,7 +226,7 @@ exports[`component Generator should inline template when --inline-template=true
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
template: \`example works!
\`,
styleUrl: './example.component.css'
})
diff --git a/packages/angular/src/generators/component/component.spec.ts b/packages/angular/src/generators/component/component.spec.ts
index 3a5f8aa2e54bef..ba264f0d2d4895 100644
--- a/packages/angular/src/generators/component/component.spec.ts
+++ b/packages/angular/src/generators/component/component.spec.ts
@@ -1,5 +1,12 @@
-import { addProjectConfiguration, writeJson } from '@nx/devkit';
+import {
+ Tree,
+ addProjectConfiguration,
+ readProjectConfiguration,
+ updateProjectConfiguration,
+ writeJson,
+} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
+import { AngularProjectConfiguration } from '../../utils/types';
import { componentGenerator } from './component';
describe('component Generator', () => {
@@ -202,7 +209,7 @@ describe('component Generator', () => {
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html'
})
export class ExampleComponent {}
@@ -885,6 +892,108 @@ export class LibModule {}
});
});
+ describe('prefix & selector', () => {
+ let tree: Tree;
+
+ beforeEach(() => {
+ tree = createTreeWithEmptyWorkspace();
+ addProjectConfiguration(tree, 'lib1', {
+ projectType: 'library',
+ root: 'lib1',
+ });
+ });
+
+ it('should use the prefix', async () => {
+ await componentGenerator(tree, {
+ name: 'lib1/src/lib/example/example',
+ prefix: 'foo',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'lib1/src/lib/example/example.component.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: 'foo-example'/);
+ });
+
+ it('should error when name starts with a digit', async () => {
+ await expect(
+ componentGenerator(tree, {
+ name: 'lib1/src/lib/1-one/1-one',
+ prefix: 'foo',
+ nameAndDirectoryFormat: 'as-provided',
+ })
+ ).rejects.toThrow('The selector "foo-1-one" is invalid.');
+ });
+
+ it('should allow dash in selector before a number', async () => {
+ await componentGenerator(tree, {
+ name: 'lib1/src/lib/one-1/one-1',
+ prefix: 'foo',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'lib1/src/lib/one-1/one-1.component.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: 'foo-one-1'/);
+ });
+
+ it('should allow dash in selector before a number and without a prefix', async () => {
+ await componentGenerator(tree, {
+ name: 'lib1/src/lib/example/example',
+ selector: 'one-1',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'lib1/src/lib/example/example.component.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: 'one-1'/);
+ });
+
+ it('should use the default project prefix if none is passed', async () => {
+ const projectConfig = readProjectConfiguration(tree, 'lib1');
+ updateProjectConfiguration(tree, 'lib1', {
+ ...projectConfig,
+ prefix: 'bar',
+ } as AngularProjectConfiguration);
+
+ await componentGenerator(tree, {
+ name: 'lib1/src/lib/example/example',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'lib1/src/lib/example/example.component.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: 'bar-example'/);
+ });
+
+ it('should not use the default project prefix when supplied prefix is ""', async () => {
+ const projectConfig = readProjectConfiguration(tree, 'lib1');
+ updateProjectConfiguration(tree, 'lib1', {
+ ...projectConfig,
+ prefix: '',
+ } as AngularProjectConfiguration);
+
+ await componentGenerator(tree, {
+ name: 'lib1/src/lib/example/example',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'lib1/src/lib/example/example.component.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: 'example'/);
+ });
+ });
+
describe('secondary entry points', () => {
it('should create the component correctly and export it in the entry point', async () => {
// ARRANGE
diff --git a/packages/angular/src/generators/component/lib/normalize-options.ts b/packages/angular/src/generators/component/lib/normalize-options.ts
index 180044ebe24a85..3f0bc08ee286ec 100644
--- a/packages/angular/src/generators/component/lib/normalize-options.ts
+++ b/packages/angular/src/generators/component/lib/normalize-options.ts
@@ -2,7 +2,7 @@ import type { Tree } from '@nx/devkit';
import { names, readProjectConfiguration } from '@nx/devkit';
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
import type { AngularProjectConfiguration } from '../../../utils/types';
-import { buildSelector } from '../../utils/selector';
+import { buildSelector, validateHtmlSelector } from '../../utils/selector';
import type { NormalizedSchema, Schema } from '../schema';
export async function normalizeOptions(
@@ -37,8 +37,8 @@ export async function normalizeOptions(
) as AngularProjectConfiguration;
const selector =
- options.selector ??
- buildSelector(tree, name, options.prefix, prefix, 'fileName');
+ options.selector ?? buildSelector(name, options.prefix, prefix, 'fileName');
+ validateHtmlSelector(selector);
return {
...options,
diff --git a/packages/angular/src/generators/directive/__snapshots__/directive.spec.ts.snap b/packages/angular/src/generators/directive/__snapshots__/directive.spec.ts.snap
index 4e3a07738ffa35..c837afba4d214b 100644
--- a/packages/angular/src/generators/directive/__snapshots__/directive.spec.ts.snap
+++ b/packages/angular/src/generators/directive/__snapshots__/directive.spec.ts.snap
@@ -16,7 +16,7 @@ exports[`directive generator --no-standalone should generate a directive with te
"import { Directive } from '@angular/core';
@Directive({
- selector: '[projTest]',
+ selector: '[test]',
})
export class TestDirective {
constructor() {}
@@ -52,7 +52,7 @@ exports[`directive generator --no-standalone should import the directive correct
"import { Directive } from '@angular/core';
@Directive({
- selector: '[projTest]'
+ selector: '[test]'
})
export class TestDirective {
constructor() {}
@@ -88,7 +88,7 @@ exports[`directive generator --no-standalone should import the directive correct
"import { Directive } from '@angular/core';
@Directive({
- selector: '[projTest]'
+ selector: '[test]'
})
export class TestDirective {
constructor() {}
@@ -124,7 +124,7 @@ exports[`directive generator should generate correctly 1`] = `
"import { Directive } from '@angular/core';
@Directive({
- selector: '[projTest]',
+ selector: '[test]',
standalone: true,
})
export class TestDirective {
diff --git a/packages/angular/src/generators/directive/directive.spec.ts b/packages/angular/src/generators/directive/directive.spec.ts
index 22bed620cf0697..94e1f344edd202 100644
--- a/packages/angular/src/generators/directive/directive.spec.ts
+++ b/packages/angular/src/generators/directive/directive.spec.ts
@@ -1,5 +1,11 @@
-import { addProjectConfiguration, Tree } from '@nx/devkit';
+import {
+ addProjectConfiguration,
+ readProjectConfiguration,
+ updateProjectConfiguration,
+ type Tree,
+} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
+import type { AngularProjectConfiguration } from '../../utils/types';
import { directiveGenerator } from './directive';
import type { Schema } from './schema';
@@ -164,6 +170,74 @@ describe('directive generator', () => {
);
});
});
+
+ describe('prefix & selector', () => {
+ it('should use the prefix', async () => {
+ await directiveGenerator(tree, {
+ name: 'test/src/app/example/example',
+ prefix: 'foo',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'test/src/app/example/example.directive.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: '\[fooExample\]'/);
+ });
+
+ it('should use the default project prefix if none is passed', async () => {
+ const projectConfig = readProjectConfiguration(tree, 'test');
+ updateProjectConfiguration(tree, 'test', {
+ ...projectConfig,
+ prefix: 'bar',
+ } as AngularProjectConfiguration);
+
+ await directiveGenerator(tree, {
+ name: 'test/src/app/example/example',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'test/src/app/example/example.directive.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: '\[barExample\]'/);
+ });
+
+ it('should not use the default project prefix when supplied prefix is ""', async () => {
+ const projectConfig = readProjectConfiguration(tree, 'test');
+ updateProjectConfiguration(tree, 'test', {
+ ...projectConfig,
+ prefix: '',
+ } as AngularProjectConfiguration);
+
+ await directiveGenerator(tree, {
+ name: 'test/src/app/example/example',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'test/src/app/example/example.directive.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: '\[example\]'/);
+ });
+
+ it('should use provided selector as is', async () => {
+ await directiveGenerator(tree, {
+ name: 'test/src/app/example/example',
+ selector: 'mySelector',
+ nameAndDirectoryFormat: 'as-provided',
+ });
+
+ const content = tree.read(
+ 'test/src/app/example/example.directive.ts',
+ 'utf-8'
+ );
+ expect(content).toMatch(/selector: '\[mySelector\]'/);
+ });
+ });
});
function addModule(tree: Tree) {
diff --git a/packages/angular/src/generators/directive/lib/normalize-options.ts b/packages/angular/src/generators/directive/lib/normalize-options.ts
index ac797d3118dbcd..c89a213a10a916 100644
--- a/packages/angular/src/generators/directive/lib/normalize-options.ts
+++ b/packages/angular/src/generators/directive/lib/normalize-options.ts
@@ -1,7 +1,7 @@
import type { Tree } from '@nx/devkit';
import { names, readProjectConfiguration } from '@nx/devkit';
import type { AngularProjectConfiguration } from '../../../utils/types';
-import { buildSelector } from '../../utils/selector';
+import { buildSelector, validateHtmlSelector } from '../../utils/selector';
import type { NormalizedSchema, Schema } from '../schema';
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
@@ -37,7 +37,8 @@ export async function normalizeOptions(
const selector =
options.selector ??
- buildSelector(tree, name, options.prefix, prefix, 'propertyName');
+ buildSelector(name, options.prefix, prefix, 'propertyName');
+ validateHtmlSelector(selector);
return {
...options,
diff --git a/packages/angular/src/generators/host/__snapshots__/host.spec.ts.snap b/packages/angular/src/generators/host/__snapshots__/host.spec.ts.snap
index 9f7c499bff352d..2e50e3c16472e1 100644
--- a/packages/angular/src/generators/host/__snapshots__/host.spec.ts.snap
+++ b/packages/angular/src/generators/host/__snapshots__/host.spec.ts.snap
@@ -954,7 +954,7 @@ import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [NxWelcomeComponent, RouterModule],
- selector: 'proj-root',
+ selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
diff --git a/packages/angular/src/generators/library/__snapshots__/library.spec.ts.snap b/packages/angular/src/generators/library/__snapshots__/library.spec.ts.snap
index d8a5ae5a362875..01c4bab972e04b 100644
--- a/packages/angular/src/generators/library/__snapshots__/library.spec.ts.snap
+++ b/packages/angular/src/generators/library/__snapshots__/library.spec.ts.snap
@@ -7,7 +7,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
@@ -53,7 +53,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
@@ -105,7 +105,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
@@ -147,7 +147,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
template: \`my-lib works!
\`,
@@ -166,7 +166,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
template: \`my-lib works!
\`,
@@ -183,7 +183,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
template: \`my-lib works!
\`,
@@ -239,7 +239,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
@@ -353,7 +353,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
@@ -395,7 +395,7 @@ exports[`lib --standalone should generate a library with a standalone component
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-my-lib',
+ selector: 'lib-my-lib',
standalone: true,
imports: [CommonModule],
templateUrl: './my-lib.component.html',
diff --git a/packages/angular/src/generators/library/lib/normalize-options.ts b/packages/angular/src/generators/library/lib/normalize-options.ts
index 11e4843071b985..73e234c0257c4f 100644
--- a/packages/angular/src/generators/library/lib/normalize-options.ts
+++ b/packages/angular/src/generators/library/lib/normalize-options.ts
@@ -1,9 +1,7 @@
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/eslint';
import { UnitTestRunner } from '../../../utils/test-runners';
-import { normalizeNewProjectPrefix } from '../../utils/project';
import { Schema } from '../schema';
import { NormalizedSchema } from './normalized-schema';
@@ -52,15 +50,12 @@ export async function normalizeOptions(
: [];
const modulePath = `${projectRoot}/src/lib/${fileName}.module.ts`;
- const npmScope = getNpmScope(host);
- const prefix = normalizeNewProjectPrefix(options.prefix, npmScope, 'lib');
-
const ngCliSchematicLibRoot = projectName;
const allNormalizedOptions = {
...options,
linter: options.linter ?? Linter.EsLint,
unitTestRunner: options.unitTestRunner ?? UnitTestRunner.Jest,
- prefix,
+ prefix: options.prefix ?? 'lib',
name: projectName,
projectRoot,
entryFile: 'index',
diff --git a/packages/angular/src/generators/library/library.spec.ts b/packages/angular/src/generators/library/library.spec.ts
index 775baa85ceb3e6..00b57d2af55493 100644
--- a/packages/angular/src/generators/library/library.spec.ts
+++ b/packages/angular/src/generators/library/library.spec.ts
@@ -652,7 +652,7 @@ describe('lib', () => {
"error",
{
"type": "attribute",
- "prefix": "proj",
+ "prefix": "lib",
"style": "camelCase"
}
],
@@ -660,7 +660,7 @@ describe('lib', () => {
"error",
{
"type": "element",
- "prefix": "proj",
+ "prefix": "lib",
"style": "kebab-case"
}
]
@@ -1201,7 +1201,7 @@ describe('lib', () => {
"@angular-eslint/component-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "lib",
"style": "kebab-case",
"type": "element",
},
@@ -1209,7 +1209,7 @@ describe('lib', () => {
"@angular-eslint/directive-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "lib",
"style": "camelCase",
"type": "attribute",
},
@@ -1261,7 +1261,7 @@ describe('lib', () => {
"@angular-eslint/component-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "lib",
"style": "kebab-case",
"type": "element",
},
@@ -1269,7 +1269,7 @@ describe('lib', () => {
"@angular-eslint/directive-selector": [
"error",
{
- "prefix": "proj",
+ "prefix": "lib",
"style": "camelCase",
"type": "attribute",
},
diff --git a/packages/angular/src/generators/remote/__snapshots__/remote.spec.ts.snap b/packages/angular/src/generators/remote/__snapshots__/remote.spec.ts.snap
index 0d49b11393ac3f..a06a027cc6f834 100644
--- a/packages/angular/src/generators/remote/__snapshots__/remote.spec.ts.snap
+++ b/packages/angular/src/generators/remote/__snapshots__/remote.spec.ts.snap
@@ -224,8 +224,8 @@ exports[`MF Remote App Generator --ssr should generate the correct files 8`] = `
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-test-entry',
- template: \`\`,
+ selector: 'app-test-entry',
+ template: \`\`,
})
export class RemoteEntryComponent {}
"
@@ -448,8 +448,8 @@ exports[`MF Remote App Generator --ssr should generate the correct files when --
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-test-entry',
- template: \`\`
+ selector: 'app-test-entry',
+ template: \`\`
})
export class RemoteEntryComponent {}
"
@@ -594,8 +594,8 @@ import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [CommonModule, NxWelcomeComponent],
- selector: 'proj-test-entry',
- template: \`\`,
+ selector: 'app-test-entry',
+ template: \`\`,
})
export class RemoteEntryComponent {}
"
@@ -657,8 +657,8 @@ import { NxWelcomeComponent } from './nx-welcome.component';
@Component({
standalone: true,
imports: [CommonModule, NxWelcomeComponent],
- selector: 'proj-test-entry',
- template: \`\`
+ selector: 'app-test-entry',
+ template: \`\`
})
export class RemoteEntryComponent {}
"
diff --git a/packages/angular/src/generators/remote/remote.spec.ts b/packages/angular/src/generators/remote/remote.spec.ts
index aa21b42b5fec6a..3a1c01883784e7 100644
--- a/packages/angular/src/generators/remote/remote.spec.ts
+++ b/packages/angular/src/generators/remote/remote.spec.ts
@@ -275,7 +275,7 @@ describe('MF Remote App Generator', () => {
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-root',
+ selector: 'app-root',
template: ''
})
@@ -294,11 +294,9 @@ describe('MF Remote App Generator', () => {
});
// ASSERT
- expect(tree.read('test/src/index.html', 'utf-8')).not.toContain(
- 'proj-root'
- );
+ expect(tree.read('test/src/index.html', 'utf-8')).not.toContain('app-root');
expect(tree.read('test/src/index.html', 'utf-8')).toContain(
- 'proj-test-entry'
+ 'app-test-entry'
);
});
diff --git a/packages/angular/src/generators/scam-directive/lib/convert-directive-to-scam.spec.ts b/packages/angular/src/generators/scam-directive/lib/convert-directive-to-scam.spec.ts
index c6c11d7496751b..a8f5efa473e730 100644
--- a/packages/angular/src/generators/scam-directive/lib/convert-directive-to-scam.spec.ts
+++ b/packages/angular/src/generators/scam-directive/lib/convert-directive-to-scam.spec.ts
@@ -47,7 +47,7 @@ describe('convertDirectiveToScam', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
@@ -159,7 +159,7 @@ describe('convertDirectiveToScam', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
@@ -272,7 +272,7 @@ describe('convertDirectiveToScam', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
@@ -332,7 +332,7 @@ describe('convertDirectiveToScam', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
diff --git a/packages/angular/src/generators/scam-directive/scam-directive.spec.ts b/packages/angular/src/generators/scam-directive/scam-directive.spec.ts
index 3e7d5c6ed81930..3f3e7b6ec56f98 100644
--- a/packages/angular/src/generators/scam-directive/scam-directive.spec.ts
+++ b/packages/angular/src/generators/scam-directive/scam-directive.spec.ts
@@ -31,7 +31,7 @@ describe('SCAM Directive Generator', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
@@ -166,7 +166,7 @@ describe('SCAM Directive Generator', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
@@ -211,7 +211,7 @@ describe('SCAM Directive Generator', () => {
import { CommonModule } from '@angular/common';
@Directive({
- selector: '[projExample]'
+ selector: '[example]'
})
export class ExampleDirective {
constructor() {}
diff --git a/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts b/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts
index b6fb58cdbb7764..a49a80b5fda892 100644
--- a/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts
+++ b/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts
@@ -36,7 +36,7 @@ describe('scam-to-standalone', () => {
@Component({
standalone: true,
imports: [CommonModule],
- selector: 'proj-bar',
+ selector: 'app-bar',
templateUrl: './bar.component.html',
styleUrl: './bar.component.css',
})
diff --git a/packages/angular/src/generators/scam/lib/convert-component-to-scam.spec.ts b/packages/angular/src/generators/scam/lib/convert-component-to-scam.spec.ts
index b3884218205157..b7ca3cd3f55d10 100644
--- a/packages/angular/src/generators/scam/lib/convert-component-to-scam.spec.ts
+++ b/packages/angular/src/generators/scam/lib/convert-component-to-scam.spec.ts
@@ -45,7 +45,7 @@ describe('convertComponentToScam', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -155,7 +155,7 @@ describe('convertComponentToScam', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -269,7 +269,7 @@ describe('convertComponentToScam', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.random.html',
styleUrl: './example.random.css'
})
@@ -384,7 +384,7 @@ describe('convertComponentToScam', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -444,7 +444,7 @@ describe('convertComponentToScam', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
diff --git a/packages/angular/src/generators/scam/scam.spec.ts b/packages/angular/src/generators/scam/scam.spec.ts
index 081fa3b8026f28..359950568f2fc6 100644
--- a/packages/angular/src/generators/scam/scam.spec.ts
+++ b/packages/angular/src/generators/scam/scam.spec.ts
@@ -30,7 +30,7 @@ describe('SCAM Generator', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -163,7 +163,7 @@ describe('SCAM Generator', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
@@ -207,7 +207,7 @@ describe('SCAM Generator', () => {
import { CommonModule } from '@angular/common';
@Component({
- selector: 'proj-example',
+ selector: 'example',
templateUrl: './example.component.html',
styleUrl: './example.component.css'
})
diff --git a/packages/angular/src/generators/setup-mf/__snapshots__/setup-mf.spec.ts.snap b/packages/angular/src/generators/setup-mf/__snapshots__/setup-mf.spec.ts.snap
index 0fbe81c63e318e..ea405b975b0018 100644
--- a/packages/angular/src/generators/setup-mf/__snapshots__/setup-mf.spec.ts.snap
+++ b/packages/angular/src/generators/setup-mf/__snapshots__/setup-mf.spec.ts.snap
@@ -262,8 +262,8 @@ exports[`Init MF should generate the remote entry component correctly when prefi
"import { Component } from '@angular/core';
@Component({
- selector: 'proj-remote1-entry',
- template: \`\`
+ selector: 'app-remote1-entry',
+ template: \`\`
})
export class RemoteEntryComponent {}
"
diff --git a/packages/angular/src/generators/setup-mf/lib/normalize-options.ts b/packages/angular/src/generators/setup-mf/lib/normalize-options.ts
index 3338e3b69dc5e2..25e7f6bbe139f0 100644
--- a/packages/angular/src/generators/setup-mf/lib/normalize-options.ts
+++ b/packages/angular/src/generators/setup-mf/lib/normalize-options.ts
@@ -10,7 +10,7 @@ export function normalizeOptions(
...options,
typescriptConfiguration: options.typescriptConfiguration ?? true,
federationType: options.federationType ?? 'static',
- prefix: options.prefix ?? getProjectPrefix(tree, options.appName),
+ prefix: options.prefix ?? getProjectPrefix(tree, options.appName) ?? 'app',
standalone: options.standalone ?? true,
};
}
diff --git a/packages/angular/src/generators/utils/project.ts b/packages/angular/src/generators/utils/project.ts
index 86213564b1b954..660ed6e9ac4350 100644
--- a/packages/angular/src/generators/utils/project.ts
+++ b/packages/angular/src/generators/utils/project.ts
@@ -1,50 +1,12 @@
import type { Tree } from '@nx/devkit';
import { readProjectConfiguration } from '@nx/devkit';
import type { AngularProjectConfiguration } from '../../utils/types';
-import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
-
-export function normalizeNewProjectPrefix(
- prefix: string | undefined,
- npmScope: string | undefined,
- fallbackPrefix: string
-): string {
- // Prefix needs to be a valid html selector, if npmScope it's not valid, we don't default
- // to it and let it fall through to the Angular schematic to handle it
- // https://github.com/angular/angular-cli/blob/aa9f0528f174e856a4923cb24861fdf6e6f96b48/packages/schematics/angular/component/index.ts#L64
- const htmlSelectorRegex =
- /^[a-zA-Z][.0-9a-zA-Z]*((:?-[0-9]+)*|(:?-[a-zA-Z][.0-9a-zA-Z]*(:?-[0-9]+)*)*)$/;
-
- if (prefix) {
- if (!htmlSelectorRegex.test(prefix)) {
- throw new Error(
- 'The provided "prefix" is invalid. The prefix must start with a letter, and must contain only alphanumeric characters or dashes.'
- );
- }
-
- return prefix;
- }
-
- if (npmScope && !htmlSelectorRegex.test(npmScope)) {
- throw new Error(`The "--prefix" option was not provided, therefore attempted to use the "npmScope" defined in "nx.json" to set the application's selector prefix, but it is invalid.
-
-There are two options that can be followed to resolve this issue:
- - Pass a valid "--prefix" option.
- - Update the "npmScope" in "nx.json" (Note: this can be an involved process, as other libraries and applications may need to be updated to match the new scope).
-
-If you encountered this error when creating a new Nx Workspace, the workspace name or "npmScope" is invalid to use as the selector prefix for the application being generated.
-
-Valid selector prefixes must start with a letter, and must contain only alphanumeric characters or dashes.`);
- }
-
- return npmScope || fallbackPrefix;
-}
export function getProjectPrefix(
tree: Tree,
project: string
): string | undefined {
return (
- (readProjectConfiguration(tree, project) as AngularProjectConfiguration)
- .prefix ?? getNpmScope(tree)
- );
+ readProjectConfiguration(tree, project) as AngularProjectConfiguration
+ ).prefix;
}
diff --git a/packages/angular/src/generators/utils/selector.ts b/packages/angular/src/generators/utils/selector.ts
index 09c8ba504ff05e..bd3ee69c0682f5 100644
--- a/packages/angular/src/generators/utils/selector.ts
+++ b/packages/angular/src/generators/utils/selector.ts
@@ -1,20 +1,26 @@
-import type { Tree } from '@nx/devkit';
import { names } from '@nx/devkit';
-import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
-
export function buildSelector(
- tree: Tree,
name: string,
prefix: string | undefined,
projectPrefix: string | undefined,
casing: keyof Pick, 'fileName' | 'propertyName'>
): string {
let selector = name;
- prefix ??= projectPrefix ?? getNpmScope(tree);
+ prefix ??= projectPrefix;
if (prefix) {
selector = `${prefix}-${selector}`;
}
return names(selector)[casing];
}
+
+// https://github.com/angular/angular-cli/blob/main/packages/schematics/angular/utility/validation.ts#L11-L14
+const htmlSelectorRegex =
+ /^[a-zA-Z][.0-9a-zA-Z]*((:?-[0-9]+)*|(:?-[a-zA-Z][.0-9a-zA-Z]*(:?-[0-9]+)*)*)$/;
+
+export function validateHtmlSelector(selector: string): void {
+ if (selector && !htmlSelectorRegex.test(selector)) {
+ throw new Error(`The selector "${selector}" is invalid.`);
+ }
+}
diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts
index 63ea240fb2a476..d82345c74056e9 100644
--- a/packages/create-nx-workspace/bin/create-nx-workspace.ts
+++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts
@@ -61,6 +61,7 @@ interface AngularArguments extends BaseArguments {
e2eTestRunner: 'none' | 'cypress' | 'playwright';
bundler: 'webpack' | 'esbuild';
ssr: boolean;
+ prefix: string;
}
interface VueArguments extends BaseArguments {
@@ -175,6 +176,10 @@ export const commandsObject: yargs.Argv = yargs
.option('ssr', {
describe: chalk.dim`Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application`,
type: 'boolean',
+ })
+ .option('prefix', {
+ describe: chalk.dim`Prefix to use for Angular component and directive selectors.`,
+ type: 'boolean',
}),
withNxCloud,
withAllPrompts,
@@ -717,6 +722,7 @@ async function determineAngularOptions(
const standaloneApi = parsedArgs.standaloneApi;
const routing = parsedArgs.routing;
+ const prefix = parsedArgs.prefix;
if (parsedArgs.preset && parsedArgs.preset !== Preset.Angular) {
preset = parsedArgs.preset;
@@ -817,6 +823,7 @@ async function determineAngularOptions(
e2eTestRunner,
bundler,
ssr,
+ prefix,
};
}
diff --git a/packages/workspace/src/generators/new/generate-preset.ts b/packages/workspace/src/generators/new/generate-preset.ts
index 5095515c1868a5..700fdad2574ed8 100644
--- a/packages/workspace/src/generators/new/generate-preset.ts
+++ b/packages/workspace/src/generators/new/generate-preset.ts
@@ -81,6 +81,7 @@ export function generatePreset(host: Tree, opts: NormalizedSchema) {
? `--e2eTestRunner=${opts.e2eTestRunner}`
: null,
opts.ssr ? `--ssr` : null,
+ opts.prefix ? `--prefix` : null,
].filter((e) => !!e);
}
}
diff --git a/packages/workspace/src/generators/new/new.ts b/packages/workspace/src/generators/new/new.ts
index ae64f1671ee56c..5213dd162ba1ef 100644
--- a/packages/workspace/src/generators/new/new.ts
+++ b/packages/workspace/src/generators/new/new.ts
@@ -34,6 +34,7 @@ interface Schema {
packageManager?: PackageManager;
e2eTestRunner?: 'cypress' | 'playwright' | 'detox' | 'jest' | 'none';
ssr?: boolean;
+ prefix?: string;
}
export interface NormalizedSchema extends Schema {
diff --git a/packages/workspace/src/generators/new/schema.json b/packages/workspace/src/generators/new/schema.json
index 000d0fa460d441..1720dab56e7a9e 100644
--- a/packages/workspace/src/generators/new/schema.json
+++ b/packages/workspace/src/generators/new/schema.json
@@ -82,6 +82,10 @@
"description": "Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application.",
"type": "boolean",
"default": false
+ },
+ "prefix": {
+ "description": "The prefix to use for Angular component and directive selectors.",
+ "type": "string"
}
},
"additionalProperties": true
diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts
index 93b77fad063e16..741429505fe0b6 100644
--- a/packages/workspace/src/generators/preset/preset.ts
+++ b/packages/workspace/src/generators/preset/preset.ts
@@ -34,6 +34,7 @@ async function createPreset(tree: Tree, options: Schema) {
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
bundler: options.bundler,
ssr: options.ssr,
+ prefix: options.prefix,
addPlugin,
});
} else if (options.preset === Preset.AngularStandalone) {
@@ -53,6 +54,7 @@ async function createPreset(tree: Tree, options: Schema) {
e2eTestRunner: options.e2eTestRunner ?? 'cypress',
bundler: options.bundler,
ssr: options.ssr,
+ prefix: options.prefix,
addPlugin,
});
} else if (options.preset === Preset.ReactMonorepo) {
diff --git a/packages/workspace/src/generators/preset/schema.d.ts b/packages/workspace/src/generators/preset/schema.d.ts
index 13fbbfbc61ded6..dff3c94c9e543f 100644
--- a/packages/workspace/src/generators/preset/schema.d.ts
+++ b/packages/workspace/src/generators/preset/schema.d.ts
@@ -18,4 +18,5 @@ export interface Schema {
e2eTestRunner?: 'cypress' | 'playwright' | 'jest' | 'detox' | 'none';
js?: boolean;
ssr?: boolean;
+ prefix?: string;
}
diff --git a/packages/workspace/src/generators/preset/schema.json b/packages/workspace/src/generators/preset/schema.json
index 1426b4947e4892..9c0b8718e05628 100644
--- a/packages/workspace/src/generators/preset/schema.json
+++ b/packages/workspace/src/generators/preset/schema.json
@@ -99,6 +99,10 @@
"description": "Enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering) for the Angular application.",
"type": "boolean",
"default": false
+ },
+ "prefix": {
+ "description": "The prefix to use for Angular component and directive selectors.",
+ "type": "string"
}
},
"required": ["preset", "name"]