fix(angular): normalize name when forced to build selector (#29417)

## Current Behavior
When passing a project name with a `/` in it to the library generator,
this name passes through to the `component` generator.
The `component` generator may then attempt to build a selector from this
name, however, it does not normalize the `/`.

## Expected Behavior
Ensure the `/` is normalized from the name when building the selector

## Related Issue(s)

Fixes #29229
This commit is contained in:
Colum Ferry 2024-12-19 15:00:53 +00:00 committed by GitHub
parent 7a583dacc6
commit 77ba049e11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 41 additions and 5 deletions

View File

@ -24,6 +24,11 @@ export async function normalizeOptions(
allowedFileExtensions: ['ts'],
fileExtension: 'ts',
});
if (name.includes('/')) {
throw new Error(
`The component name '${name}' cannot contain a slash as it must be a valid JS symbol. Please use a different name.`
);
}
const { className } = names(name);
const { className: suffixClassName } = names(options.type);

View File

@ -146,7 +146,7 @@ import { CommonModule } from '@angular/common';
@Component({
selector: 'lib-my-lib',
imports: [CommonModule],
template: \`<p>my-lib works!</p>\`,
template: \`<p>MyLib works!</p>\`,
styles: \`\`,
encapsulation: ViewEncapsulation.ShadowDom,
changeDetection: ChangeDetectionStrategy.OnPush
@ -164,7 +164,7 @@ import { CommonModule } from '@angular/common';
@Component({
selector: 'lib-my-lib',
imports: [CommonModule],
template: \`<p>my-lib works!</p>\`,
template: \`<p>MyLib works!</p>\`,
styles: \`\`
})
export class MyLibComponent {}
@ -180,7 +180,7 @@ import { CommonModule } from '@angular/common';
@Component({
selector: 'lib-my-lib',
imports: [CommonModule],
template: \`<p>my-lib works!</p>\`,
template: \`<p>MyLib works!</p>\`,
styles: \`\`
})
export class MyLibComponent {}
@ -421,6 +421,22 @@ describe('MyLibComponent', () => {
"
`;
exports[`lib --standalone should generate a library with a valid selector for the standalone component when library name has a slash 1`] = `"export * from './lib/auth/common/auth/common.component';"`;
exports[`lib --standalone should generate a library with a valid selector for the standalone component when library name has a slash 2`] = `
"import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'lib-auth-common',
imports: [CommonModule],
templateUrl: './common.component.html',
styleUrl: './common.component.css'
})
export class AuthCommonComponent {}
"
`;
exports[`lib router lazy should add RouterModule.forChild 1`] = `
"import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';

View File

@ -1,4 +1,4 @@
import { joinPathFragments, type Tree } from '@nx/devkit';
import { joinPathFragments, names, type Tree } from '@nx/devkit';
import { componentGenerator } from '../../component/component';
import { addChildren } from './add-children';
import { addLoadChildren } from './add-load-children';
@ -10,7 +10,7 @@ export async function addStandaloneComponent(
) {
await componentGenerator(tree, {
...componentOptions,
name: componentOptions.name,
name: names(libraryOptions.name).className,
path: joinPathFragments(
libraryOptions.projectRoot,
'src',

View File

@ -1491,6 +1491,21 @@ describe('lib', () => {
).toMatchSnapshot();
});
it('should generate a library with a valid selector for the standalone component when library name has a slash', async () => {
await runLibraryGeneratorWithOpts({
standalone: true,
name: 'auth/common',
});
expect(tree.read('my-lib/src/index.ts', 'utf-8')).toMatchSnapshot();
expect(
tree.read(
'my-lib/src/lib/auth/common/auth/common.component.ts',
'utf-8'
)
).toMatchSnapshot();
});
it('should generate a library with a standalone component and have it flat', async () => {
await runLibraryGeneratorWithOpts({ standalone: true, flat: true });