Skip to content

Commit 4620b40

Browse files
committed
feat(angular): generate components without a .component/Component suffix/type
1 parent 3b14976 commit 4620b40

File tree

94 files changed

+2497
-1533
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

94 files changed

+2497
-1533
lines changed

docs/generated/packages/angular/generators/component.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,7 @@
9595
},
9696
"type": {
9797
"type": "string",
98-
"description": "Adds a developer-defined type to the filename, in the format `name.type.ts`.",
99-
"default": "component"
98+
"description": "Append a custom type to the component's filename. It defaults to 'component' for Angular versions below v20. For Angular v20 and above, no type is appended unless specified."
10099
},
101100
"export": {
102101
"type": "boolean",
@@ -122,7 +121,7 @@
122121
}
123122
},
124123
"required": ["path"],
125-
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component.ts\n```\n\n{% /tab %}\n\n{% tab label=\"Without Providing the File Extension\" %}\n\nGenerate a component named `MyComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component\n```\n\n{% /tab %}\n\n{% tab label=\"With Different Symbol Name\" %}\n\nGenerate a component named `CustomComponent` at `apps/my-app/src/lib/my-component/my-component.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"Single File Component\" %}\n\nCreate a component named `my-component` with inline styles and inline template:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --inlineStyle --inlineTemplate\n```\n\n{% /tab %}\n\n{% tab label=\"Component with OnPush Change Detection Strategy\" %}\n\nCreate a component named `my-component` with OnPush Change Detection Strategy:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/my-component/my-component --changeDetection=OnPush\n```\n\n{% /tab %}\n",
124+
"examplesFile": "## Examples\n\n{% tabs %}\n{% tab label=\"Simple Component\" %}\n\nGenerate a component named `Card` at `apps/my-app/src/lib/card/card.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card.ts\n```\n\n{% /tab %}\n\n{% tab label=\"Without Providing the File Extension\" %}\n\nGenerate a component named `Card` at `apps/my-app/src/lib/card/card.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card\n```\n\n{% /tab %}\n\n{% tab label=\"With Different Symbol Name\" %}\n\nGenerate a component named `Custom` at `apps/my-app/src/lib/card/card.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card --name=custom\n```\n\n{% /tab %}\n\n{% tab label=\"With a Component Type\" %}\n\nGenerate a component named `CardComponent` at `apps/my-app/src/lib/card/card.component.ts`:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card --type=component\n```\n\n{% /tab %}\n\n{% tab label=\"Single File Component\" %}\n\nCreate a component named `Card` with inline styles and inline template:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card --inlineStyle --inlineTemplate\n```\n\n{% /tab %}\n\n{% tab label=\"Component with OnPush Change Detection Strategy\" %}\n\nCreate a component named `Card` with `OnPush` Change Detection Strategy:\n\n```bash\nnx g @nx/angular:component apps/my-app/src/lib/card/card --changeDetection=OnPush\n```\n\n{% /tab %}\n",
126125
"presets": []
127126
},
128127
"aliases": ["c"],

docs/generated/packages/angular/generators/scam.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@
9494
},
9595
"type": {
9696
"type": "string",
97-
"description": "Adds a developer-defined type to the filename, in the format `name.type.ts`.",
98-
"default": "component"
97+
"description": "Append a custom type to the component's filename. It defaults to 'component' for Angular versions below v20. For Angular v20 and above, no type is appended unless specified."
9998
},
10099
"prefix": {
101100
"type": "string",

e2e/angular/src/cypress-component-tests.test.ts

Lines changed: 37 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,12 @@ describe('Angular Cypress Component Tests', () => {
8080
}
8181
// add tailwind
8282
runCLI(`generate @nx/angular:setup-tailwind --project=${buildableLibName}`);
83+
updateFile(`${buildableLibName}/src/lib/input/input.cy.ts`, (content) => {
84+
// text-green-500 should now apply
85+
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
86+
});
8387
updateFile(
84-
`${buildableLibName}/src/lib/input/input.component.cy.ts`,
85-
(content) => {
86-
// text-green-500 should now apply
87-
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
88-
}
89-
);
90-
updateFile(
91-
`${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
88+
`${buildableLibName}/src/lib/input-standalone/input-standalone.cy.ts`,
9289
(content) => {
9390
// text-green-500 should now apply
9491
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
@@ -149,7 +146,7 @@ function createLib(projectName: string, appName: string, libName: string) {
149146
`generate @nx/angular:component ${libName}/src/lib/btn-standalone/btn-standalone --inlineTemplate --inlineStyle --export --standalone --no-interactive`
150147
);
151148
updateFile(
152-
`${libName}/src/lib/btn/btn.component.ts`,
149+
`${libName}/src/lib/btn/btn.ts`,
153150
`
154151
import { Component, Input } from '@angular/core';
155152
@@ -158,13 +155,13 @@ import { Component, Input } from '@angular/core';
158155
template: '<button class="text-green-500">{{text}}</button>',
159156
styles: []
160157
})
161-
export class BtnComponent {
158+
export class Btn {
162159
@Input() text = 'something';
163160
}
164161
`
165162
);
166163
updateFile(
167-
`${libName}/src/lib/btn-standalone/btn-standalone.component.ts`,
164+
`${libName}/src/lib/btn-standalone/btn-standalone.ts`,
168165
`
169166
import { Component, Input } from '@angular/core';
170167
import { CommonModule } from '@angular/common';
@@ -175,7 +172,7 @@ import { CommonModule } from '@angular/common';
175172
template: '<button class="text-green-500">standlone-{{text}}</button>',
176173
styles: [],
177174
})
178-
export class BtnStandaloneComponent {
175+
export class BtnStandalone {
179176
@Input() text = 'something';
180177
}
181178
`
@@ -195,7 +192,7 @@ function createBuildableLib(projectName: string, libName: string) {
195192
);
196193
// update cmp implmentation to use tailwind clasasserting in tests
197194
updateFile(
198-
`${libName}/src/lib/input/input.component.ts`,
195+
`${libName}/src/lib/input/input.ts`,
199196
`
200197
import {Component, Input} from '@angular/core';
201198
@@ -204,13 +201,13 @@ import {Component, Input} from '@angular/core';
204201
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
205202
styles : []
206203
})
207-
export class InputComponent{
204+
export class Input{
208205
@Input() readOnly = false;
209206
}
210207
`
211208
);
212209
updateFile(
213-
`${libName}/src/lib/input-standalone/input-standalone.component.ts`,
210+
`${libName}/src/lib/input-standalone/input-standalone.ts`,
214211
`
215212
import {Component, Input} from '@angular/core';
216213
import {CommonModule} from '@angular/common';
@@ -221,7 +218,7 @@ import {CommonModule} from '@angular/common';
221218
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
222219
styles : []
223220
})
224-
export class InputStandaloneComponent{
221+
export class InputStandalone{
225222
@Input() readOnly = false;
226223
}
227224
`
@@ -230,7 +227,7 @@ import {CommonModule} from '@angular/common';
230227

231228
function useLibInApp(projectName: string, appName: string, libName: string) {
232229
createFile(
233-
`${appName}/src/app/app.component.html`,
230+
`${appName}/src/app/app.html`,
234231
`
235232
<${projectName}-btn></${projectName}-btn>
236233
<${projectName}-btn-standalone></${projectName}-btn-standalone>
@@ -239,7 +236,7 @@ function useLibInApp(projectName: string, appName: string, libName: string) {
239236
);
240237
const btnModuleName = names(libName).className;
241238
updateFile(
242-
`${appName}/src/app/app.component.scss`,
239+
`${appName}/src/app/app.scss`,
243240
`
244241
@use 'styleguide' as *;
245242
@@ -254,14 +251,14 @@ import { NgModule } from '@angular/core';
254251
import { BrowserModule } from '@angular/platform-browser';
255252
import {${btnModuleName}Module} from "@${projectName}/${libName}";
256253
257-
import { AppComponent } from './app.component';
258-
import { NxWelcomeComponent } from './nx-welcome.component';
254+
import { App } from './app';
255+
import { NxWelcome } from './nx-welcome';
259256
260257
@NgModule({
261-
declarations: [AppComponent, NxWelcomeComponent],
258+
declarations: [App, NxWelcome],
262259
imports: [BrowserModule, ${btnModuleName}Module],
263260
providers: [],
264-
bootstrap: [AppComponent],
261+
bootstrap: [App],
265262
})
266263
export class AppModule {}
267264
`
@@ -297,25 +294,25 @@ async function useWorkspaceAssetsInApp(appName: string) {
297294

298295
function updateTestToAssertTailwindIsNotApplied(libName: string) {
299296
createFile(
300-
`${libName}/src/lib/input/input.component.cy.ts`,
297+
`${libName}/src/lib/input/input.cy.ts`,
301298
`
302299
import { MountConfig } from 'cypress/angular';
303-
import { InputComponent } from './input.component';
300+
import { Input } from './input';
304301
305-
describe(InputComponent.name, () => {
306-
const config: MountConfig<InputComponent> = {
302+
describe(Input.name, () => {
303+
const config: MountConfig<Input> = {
307304
declarations: [],
308305
imports: [],
309306
providers: [],
310307
};
311308
312309
it('renders', () => {
313-
cy.mount(InputComponent, config);
310+
cy.mount(Input, config);
314311
// make sure tailwind isn't getting applied
315312
cy.get('label').should('have.css', 'color', 'rgb(0, 0, 0)');
316313
});
317314
it('should be readonly', () => {
318-
cy.mount(InputComponent, {
315+
cy.mount(Input, {
319316
...config,
320317
componentProperties: {
321318
readOnly: true,
@@ -328,25 +325,25 @@ describe(InputComponent.name, () => {
328325
);
329326

330327
createFile(
331-
`${libName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
328+
`${libName}/src/lib/input-standalone/input-standalone.cy.ts`,
332329
`
333330
import { MountConfig } from 'cypress/angular';
334-
import { InputStandaloneComponent } from './input-standalone.component';
331+
import { InputStandalone } from './input-standalone';
335332
336-
describe(InputStandaloneComponent.name, () => {
337-
const config: MountConfig<InputStandaloneComponent> = {
333+
describe(InputStandalone.name, () => {
334+
const config: MountConfig<InputStandalone> = {
338335
declarations: [],
339336
imports: [],
340337
providers: [],
341338
};
342339
343340
it('renders', () => {
344-
cy.mount(InputStandaloneComponent, config);
341+
cy.mount(InputStandalone, config);
345342
// make sure tailwind isn't getting applied
346343
cy.get('label').should('have.css', 'color', 'rgb(0, 0, 0)');
347344
});
348345
it('should be readonly', () => {
349-
cy.mount(InputStandaloneComponent, {
346+
cy.mount(InputStandalone, {
350347
...config,
351348
componentProperties: {
352349
readOnly: true,
@@ -367,19 +364,19 @@ function useBuildableLibInLib(
367364
const buildLibNames = names(buildableLibName);
368365
// use the buildable lib in lib so now buildableLib has an indirect dep on app
369366
updateFile(
370-
`${libName}/src/lib/btn-standalone/btn-standalone.component.ts`,
367+
`${libName}/src/lib/btn-standalone/btn-standalone.ts`,
371368
`
372369
import { Component, Input } from '@angular/core';
373370
import { CommonModule } from '@angular/common';
374-
import { InputStandaloneComponent } from '@${projectName}/${buildLibNames.fileName}';
371+
import { InputStandalone } from '@${projectName}/${buildLibNames.fileName}';
375372
@Component({
376373
selector: '${projectName}-btn-standalone',
377374
standalone: true,
378-
imports: [CommonModule, InputStandaloneComponent],
375+
imports: [CommonModule, InputStandalone],
379376
template: '<button class="text-green-500">standlone-{{text}}</button>${projectName} <${projectName}-input-standalone></${projectName}-input-standalone>',
380377
styles: [],
381378
})
382-
export class BtnStandaloneComponent {
379+
export class BtnStandalone {
383380
@Input() text = 'something';
384381
}
385382
`
@@ -392,9 +389,9 @@ function updateBuilableLibTestsToAssertAppStyles(
392389
) {
393390
updateFile(`${appName}/src/styles.css`, `label {color: pink !important;}`);
394391

395-
removeFile(`${buildableLibName}/src/lib/input/input.component.cy.ts`);
392+
removeFile(`${buildableLibName}/src/lib/input/input.cy.ts`);
396393
updateFile(
397-
`${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
394+
`${buildableLibName}/src/lib/input-standalone/input-standalone.cy.ts`,
398395
(content) => {
399396
// app styles should now apply
400397
return content.replace('rgb(34, 197, 94)', 'rgb(255, 192, 203)');

e2e/angular/src/misc.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,8 @@ describe('Move Angular Project', () => {
4545
expect(moveOutput).toContain(`CREATE ${newPath}/src/main.ts`);
4646
expect(moveOutput).toContain(`CREATE ${newPath}/src/styles.css`);
4747
expect(moveOutput).toContain(`CREATE ${newPath}/src/test-setup.ts`);
48-
expect(moveOutput).toContain(
49-
`CREATE ${newPath}/src/app/app.component.html`
50-
);
51-
expect(moveOutput).toContain(`CREATE ${newPath}/src/app/app.component.ts`);
48+
expect(moveOutput).toContain(`CREATE ${newPath}/src/app/app.html`);
49+
expect(moveOutput).toContain(`CREATE ${newPath}/src/app/app.ts`);
5250
expect(moveOutput).toContain(`CREATE ${newPath}/src/app/app.config.ts`);
5351
});
5452

e2e/angular/src/module-federation.test.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,12 @@ describe('Angular Module Federation', () => {
9494
import { ${
9595
names(secondaryEntry).className
9696
}Module } from '@${proj}/${sharedLib}/${secondaryEntry}';
97-
import { AppComponent } from './app.component';
98-
import { NxWelcomeComponent } from './nx-welcome.component';
97+
import { App } from './app';
98+
import { NxWelcome } from './nx-welcome';
9999
import { RouterModule } from '@angular/router';
100100
101101
@NgModule({
102-
declarations: [AppComponent, NxWelcomeComponent],
102+
declarations: [App, NxWelcome],
103103
imports: [
104104
BrowserModule,
105105
${names(sharedLib).className}Module,
@@ -118,7 +118,7 @@ describe('Angular Module Federation', () => {
118118
),
119119
],
120120
providers: [],
121-
bootstrap: [AppComponent],
121+
bootstrap: [App],
122122
})
123123
export class AppModule {}
124124
`
@@ -132,18 +132,18 @@ describe('Angular Module Federation', () => {
132132
import { ${
133133
names(secondaryEntry).className
134134
}Module } from '@${proj}/${sharedLib}/${secondaryEntry}';
135-
import { RemoteEntryComponent } from './entry.component';
136-
import { NxWelcomeComponent } from './nx-welcome.component';
135+
import { RemoteEntry } from './entry';
136+
import { NxWelcome } from './nx-welcome';
137137
138138
@NgModule({
139-
declarations: [RemoteEntryComponent, NxWelcomeComponent],
139+
declarations: [RemoteEntry, NxWelcome],
140140
imports: [
141141
CommonModule,
142142
${names(sharedLib).className}Module,
143143
RouterModule.forChild([
144144
{
145145
path: '',
146-
component: RemoteEntryComponent,
146+
component: RemoteEntry,
147147
},
148148
]),
149149
],
@@ -301,7 +301,7 @@ test('renders remotes', async ({ page }) => {
301301

302302
// Update Host to use the module
303303
updateFile(
304-
`${host}/src/app/app.component.ts`,
304+
`${host}/src/app/app.ts`,
305305
`
306306
import { Component } from '@angular/core';
307307
import { isEven } from '${remote}/${module}';
@@ -311,7 +311,7 @@ test('renders remotes', async ({ page }) => {
311311
template: \`<div class="host">{{title}}</div>\`,
312312
standalone: true
313313
})
314-
export class AppComponent {
314+
export class App {
315315
title = \`shell is \${isEven(2) ? 'even' : 'odd'}\`;
316316
}`
317317
);
@@ -373,7 +373,7 @@ test('renders remotes', async ({ page }) => {
373373

374374
// Update Host to use the module
375375
updateFile(
376-
`${remote}/src/app/remote-entry/entry.component.ts`,
376+
`${remote}/src/app/remote-entry/entry.ts`,
377377
`
378378
import { Component } from '@angular/core';
379379
import { isEven } from '${childRemote}/${module}';
@@ -383,7 +383,7 @@ test('renders remotes', async ({ page }) => {
383383
template: \`<div class="childremote">{{title}}</div>\`,
384384
standalone: true
385385
})
386-
export class RemoteEntryComponent {
386+
export class RemoteEntry {
387387
title = \`shell is \${isEven(2) ? 'even' : 'odd'}\`;
388388
}`
389389
);
@@ -398,7 +398,7 @@ test('renders remotes', async ({ page }) => {
398398
remotes: ['${childRemote}'],
399399
exposes: {
400400
'./Routes': '${remote}/src/app/remote-entry/entry.routes.ts',
401-
'./Module': '${remote}/src/app/remote-entry/entry.component.ts',
401+
'./Module': '${remote}/src/app/remote-entry/entry.ts',
402402
},
403403
};
404404

0 commit comments

Comments
 (0)