fix(@schematics/angular): generate components without a .component extension/type

To align with the updated style guide, Angular v20 will generate components
without a `.component` file extension type for all component related
files by default. Projects will automatically use this naming convention.
Projects can however opt-out by setting the `type` option to `Component`
for the component schematic. This can be done as a default in the `angular.json`
or directly on the commandline via `--type=Component` when executing `ng generate`.
As an example, `app.component.css` will now be named `app.css`. Additionally,
the TypeScript class name will be `App` instead of the previous `AppComponent`.
This commit is contained in:
Charles Lyding 2025-03-10 11:56:47 -04:00 committed by Douglas Parker
parent f126f8d34b
commit 23fc8e1e17
94 changed files with 399 additions and 453 deletions

View File

@ -182,7 +182,7 @@ function addServerRoutes(options: AppShellOptions): Rule {
.filter((node) => node.kind === ts.SyntaxKind.ImportDeclaration)
.sort((a, b) => a.getStart() - b.getStart());
const insertPosition = imports[imports.length - 1].getEnd();
const routeText = `\n\nconst routes: Routes = [ { path: '${APP_SHELL_ROUTE}', component: AppShellComponent }];`;
const routeText = `\n\nconst routes: Routes = [ { path: '${APP_SHELL_ROUTE}', component: AppShell }];`;
recorder.insertRight(insertPosition, routeText);
host.commitUpdate(recorder);
}
@ -262,7 +262,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
multi: true,
useValue: [{
path: '${APP_SHELL_ROUTE}',
component: AppShellComponent
component: AppShell
}]
}\n `,
];
@ -270,12 +270,7 @@ function addStandaloneServerRoute(options: AppShellOptions): Rule {
recorder.insertRight(providersLiteral.getStart(), `[\n${updatedProvidersString.join(',\n')}]`);
applyToUpdateRecorder(recorder, [
insertImport(
configSourceFile,
configFilePath,
'AppShellComponent',
'./app-shell/app-shell.component',
),
insertImport(configSourceFile, configFilePath, 'AppShell', './app-shell/app-shell'),
]);
host.commitUpdate(recorder);
};
@ -315,16 +310,11 @@ function addServerRoutingConfig(options: AppShellOptions, isStandalone: boolean)
}
recorder = host.beginUpdate(configFilePath);
recorder.insertLeft(functionCall.end - 1, `, withAppShell(AppShellComponent)`);
recorder.insertLeft(functionCall.end - 1, `, withAppShell(AppShell)`);
applyToUpdateRecorder(recorder, [
insertImport(configSourceFile, configFilePath, 'withAppShell', '@angular/ssr'),
insertImport(
configSourceFile,
configFilePath,
'AppShellComponent',
'./app-shell/app-shell.component',
),
insertImport(configSourceFile, configFilePath, 'AppShell', './app-shell/app-shell'),
]);
host.commitUpdate(recorder);

View File

@ -82,14 +82,14 @@ describe('App Shell Schematic', () => {
it('should work if server config was added prior to running the app-shell schematic', async () => {
let tree = await schematicRunner.runSchematic('server', defaultOptions, appTree);
tree = await schematicRunner.runSchematic('app-shell', defaultOptions, tree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
});
it('should create the shell component', async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
const content = tree.readContent('/projects/bar/src/app/app.module.server.ts');
expect(content).toMatch(/app-shell\.component/);
expect(content).toMatch(/app-shell/);
});
});
@ -117,27 +117,25 @@ describe('App Shell Schematic', () => {
it('should create the shell component', async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.component.ts')).toBe(true);
expect(tree.exists('/projects/bar/src/app/app-shell/app-shell.ts')).toBe(true);
const content = tree.readContent('/projects/bar/src/app/app.config.server.ts');
expect(content).toMatch(/app-shell\.component/);
expect(content).toMatch(/app-shell/);
});
it(`should update the 'provideServerRouting' call to include 'withAppShell'`, async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
const content = tree.readContent('/projects/bar/src/app/app.config.server.ts');
expect(tags.oneLine`${content}`).toContain(
tags.oneLine`provideServerRouting(serverRoutes, withAppShell(AppShellComponent))`,
tags.oneLine`provideServerRouting(serverRoutes, withAppShell(AppShell))`,
);
});
it(`should add import to 'AppShellComponent'`, async () => {
it(`should add import to 'AppShell'`, async () => {
const tree = await schematicRunner.runSchematic('app-shell', defaultOptions, appTree);
const filePath = '/projects/bar/src/app/app.config.server.ts';
const content = tree.readContent(filePath);
expect(content).toContain(
`import { AppShellComponent } from './app-shell/app-shell.component';`,
);
expect(content).toContain(`import { AppShell } from './app-shell/app-shell';`);
});
});
});

View File

@ -2,17 +2,17 @@ import { NgModule<% if(experimentalZoneless) { %>, provideExperimentalZonelessCh
import { BrowserModule } from '@angular/platform-browser';
<% if (routing) { %>
import { AppRoutingModule } from './app-routing.module';<% } %>
import { AppComponent } from './app.component';
import { App } from './app';
@NgModule({
declarations: [
AppComponent
App
],
imports: [
BrowserModule<% if (routing) { %>,
AppRoutingModule<% } %>
],
providers: [<% if (experimentalZoneless) { %>provideExperimentalZonelessChangeDetection()<% } %>],
bootstrap: [AppComponent]
bootstrap: [App]
})
export class AppModule { }

View File

@ -1,35 +1,35 @@
<% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core';
<% } %>import { TestBed } from '@angular/core/testing';<% if (routing) { %>
import { RouterModule } from '@angular/router';<% } %>
import { AppComponent } from './app.component';
import { App } from './app';
describe('AppComponent', () => {
describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({<% if (routing) { %>
imports: [
RouterModule.forRoot([])
],<% } %>
declarations: [
AppComponent
App
],<% if(experimentalZoneless) { %>
providers: [provideExperimentalZonelessChangeDetection()]<% } %>
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title '<%= name %>'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app.title).toEqual('<%= name %>');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');

View File

@ -9,11 +9,11 @@ import { Component } from '@angular/core';
%><router-outlet /><%
} %>
`,<% } else { %>
templateUrl: './app.component.ng.html',<% } %>
templateUrl: './app.ng.html',<% } %>
standalone: false,<% if(inlineStyle) { %>
styles: []<% } else { %>
styleUrl: './app.component.<%= style %>'<% } %>
styleUrl: './app.<%= style %>'<% } %>
})
export class AppComponent {
export class App {
title = '<%= name %>';
}

View File

@ -1,29 +1,29 @@
<% if(experimentalZoneless) { %>import { provideExperimentalZonelessChangeDetection } from '@angular/core';
<% } %>import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { App } from './app';
describe('AppComponent', () => {
describe('App', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AppComponent],<% if(experimentalZoneless) { %>
imports: [App],<% if(experimentalZoneless) { %>
providers: [provideExperimentalZonelessChangeDetection()]<% } %>
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have the '<%= name %>' title`, () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
const app = fixture.componentInstance;
expect(app.title).toEqual('<%= name %>');
});
it('should render title', () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
fixture.detectChanges();
const compiled = fixture.nativeElement as HTMLElement;
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, <%= name %>');

View File

@ -11,10 +11,10 @@ import { RouterOutlet } from '@angular/router';<% } %>
%><router-outlet /><%
} %>
`,<% } else { %>
templateUrl: './app.component.ng.html',<% } if(inlineStyle) { %>
templateUrl: './app.ng.html',<% } if(inlineStyle) { %>
styles: [],<% } else { %>
styleUrl: './app.component.<%= style %>'<% } %>
styleUrl: './app.<%= style %>'<% } %>
})
export class AppComponent {
export class App {
title = '<%= name %>';
}

View File

@ -1,6 +1,6 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';
import { App } from './app/app';
bootstrapApplication(AppComponent, appConfig)
bootstrapApplication(App, appConfig)
.catch((err) => console.error(err));

View File

@ -55,10 +55,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/main.ts',
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app.module.ts',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.ts',
]),
);
});
@ -265,10 +265,10 @@ describe('Application Schematic', () => {
'/src/index.html',
'/src/main.ts',
'/src/styles.css',
'/src/app/app.component.css',
'/src/app/app.component.ng.html',
'/src/app/app.component.spec.ts',
'/src/app/app.component.ts',
'/src/app/app.css',
'/src/app/app.ng.html',
'/src/app/app.spec.ts',
'/src/app/app.ts',
]),
);
});
@ -446,9 +446,9 @@ describe('Application Schematic', () => {
const files = tree.files;
[
'/projects/foo/tsconfig.spec.json',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual(
@ -458,7 +458,7 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html',
'/projects/foo/src/main.ts',
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.ts',
]),
);
});
@ -472,8 +472,8 @@ describe('Application Schematic', () => {
'/projects/foo/tsconfig.spec.json',
'/projects/foo/karma.conf.js',
'/projects/foo/src/test.ts',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual(
@ -483,8 +483,8 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html',
'/projects/foo/src/main.ts',
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.ts',
]),
);
});
@ -498,8 +498,8 @@ describe('Application Schematic', () => {
'/projects/foo/tsconfig.spec.json',
'/projects/foo/karma.conf.js',
'/projects/foo/src/test.ts',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.spec.ts',
].forEach((x) => expect(files).not.toContain(x));
expect(files).toEqual(
@ -509,8 +509,8 @@ describe('Application Schematic', () => {
'/projects/foo/src/index.html',
'/projects/foo/src/main.ts',
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.ts',
]),
);
});
@ -530,10 +530,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/main.ts',
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app.config.ts',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.ts',
]),
);
});
@ -557,7 +557,7 @@ describe('Application Schematic', () => {
it('should create a standalone component', async () => {
const options = { ...defaultOptions, standalone: true };
const tree = await schematicRunner.runSchematic('application', options, workspaceTree);
const component = tree.readContent('/projects/foo/src/app/app.component.ts');
const component = tree.readContent('/projects/foo/src/app/app.ts');
expect(component).not.toContain('standalone');
});
@ -569,7 +569,7 @@ describe('Application Schematic', () => {
expect(tree.files).toContain('/projects/foo/src/app/app.routes.ts');
const component = tree.readContent('/projects/foo/src/app/app.component.ts');
const component = tree.readContent('/projects/foo/src/app/app.ts');
expect(component).toContain(`import { RouterOutlet } from '@angular/router';`);
expect(component).toContain(`imports: [RouterOutlet]`);
@ -654,7 +654,7 @@ describe('Application Schematic', () => {
const path = '/projects/foo/src/app/app.module.ts';
const content = tree.readContent(path);
expect(content).toMatch(/import { AppComponent } from '\.\/app\.component';/);
expect(content).toMatch(/import { App } from '\.\/app';/);
});
it('should create all files of an application', async () => {
@ -671,10 +671,10 @@ describe('Application Schematic', () => {
'/projects/foo/src/styles.css',
'/projects/foo/src/app/app-routing.module.ts',
'/projects/foo/src/app/app.module.ts',
'/projects/foo/src/app/app.component.css',
'/projects/foo/src/app/app.component.ng.html',
'/projects/foo/src/app/app.component.spec.ts',
'/projects/foo/src/app/app.component.ts',
'/projects/foo/src/app/app.css',
'/projects/foo/src/app/app.ng.html',
'/projects/foo/src/app/app.spec.ts',
'/projects/foo/src/app/app.ts',
]),
);
});

View File

@ -55,6 +55,9 @@ export default function (options: ComponentOptions): Rule {
options.module = findModuleFromOptions(host, options);
// Schematic templates require a defined type value
options.type ??= '';
const parsedPath = parseName(options.path, options.name);
options.name = parsedPath.name;
options.path = parsedPath.path;

View File

@ -93,8 +93,7 @@
},
"type": {
"type": "string",
"description": "Append a custom type to the component's filename. For example, if you set the type to `container`, the file will be named `my-component.container.ts`.",
"default": "Component"
"description": "Append a custom type to the component's filename. For example, if you set the type to `container`, the file will be named `my-component.container.ts`."
},
"skipTests": {
"type": "boolean",

View File

@ -3,5 +3,5 @@
*/
export * from './lib/<%= dasherize(name) %>.service';
export * from './lib/<%= dasherize(name) %>.component';<% if (!standalone) { %>
export * from './lib/<%= dasherize(name) %>';<% if (!standalone) { %>
export * from './lib/<%= dasherize(name) %>.module';<% } %>

View File

@ -55,8 +55,8 @@ describe('Library Schematic', () => {
'/projects/foo/tsconfig.lib.json',
'/projects/foo/tsconfig.lib.prod.json',
'/projects/foo/src/my-index.ts',
'/projects/foo/src/lib/foo.component.spec.ts',
'/projects/foo/src/lib/foo.component.ts',
'/projects/foo/src/lib/foo.spec.ts',
'/projects/foo/src/lib/foo.ts',
'/projects/foo/src/lib/foo.service.spec.ts',
'/projects/foo/src/lib/foo.service.ts',
]),
@ -70,7 +70,7 @@ describe('Library Schematic', () => {
it('should create a standalone component', async () => {
const tree = await schematicRunner.runSchematic('library', defaultOptions, workspaceTree);
const componentContent = tree.readContent('/projects/foo/src/lib/foo.component.ts');
const componentContent = tree.readContent('/projects/foo/src/lib/foo.ts');
expect(componentContent).not.toContain('standalone');
});
@ -100,8 +100,8 @@ describe('Library Schematic', () => {
'/some/other/directory/bar/tsconfig.lib.json',
'/some/other/directory/bar/tsconfig.lib.prod.json',
'/some/other/directory/bar/src/my-index.ts',
'/some/other/directory/bar/src/lib/foo.component.spec.ts',
'/some/other/directory/bar/src/lib/foo.component.ts',
'/some/other/directory/bar/src/lib/foo.spec.ts',
'/some/other/directory/bar/src/lib/foo.ts',
'/some/other/directory/bar/src/lib/foo.service.spec.ts',
'/some/other/directory/bar/src/lib/foo.service.ts',
]),
@ -310,7 +310,7 @@ describe('Library Schematic', () => {
project: 'foo',
};
tree = await schematicRunner.runSchematic('component', componentOptions, tree);
expect(tree.exists('/projects/foo/src/lib/comp/comp.component.ts')).toBe(true);
expect(tree.exists('/projects/foo/src/lib/comp/comp.ts')).toBe(true);
});
it(`should support creating scoped libraries`, async () => {
@ -321,7 +321,7 @@ describe('Library Schematic', () => {
const pkgJsonPath = '/projects/myscope/mylib/package.json';
expect(tree.files).toContain(pkgJsonPath);
expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.service.ts');
expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.component.ts');
expect(tree.files).toContain('/projects/myscope/mylib/src/lib/mylib.ts');
const pkgJson = JSON.parse(tree.readContent(pkgJsonPath));
expect(pkgJson.name).toEqual(scopedName);
@ -409,7 +409,7 @@ describe('Library Schematic', () => {
);
const fileContent = getFileContent(tree, '/projects/foo/src/lib/foo.module.ts');
expect(fileContent).toMatch(/exports: \[\n(\s*) {2}FooComponent\n\1\]/);
expect(fileContent).toMatch(/exports: \[\n(\s*) {2}Foo\n\1\]/);
});
it('should create files', async () => {
@ -429,8 +429,8 @@ describe('Library Schematic', () => {
'/projects/foo/tsconfig.lib.prod.json',
'/projects/foo/src/my-index.ts',
'/projects/foo/src/lib/foo.module.ts',
'/projects/foo/src/lib/foo.component.spec.ts',
'/projects/foo/src/lib/foo.component.ts',
'/projects/foo/src/lib/foo.spec.ts',
'/projects/foo/src/lib/foo.ts',
'/projects/foo/src/lib/foo.service.spec.ts',
'/projects/foo/src/lib/foo.service.ts',
]),

View File

@ -1,8 +1,8 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';<% if (lazyRoute) { %>
import { <%= classify(name) %>Component } from './<%= dasherize(name) %>.component';<% } %>
import { <%= classify(name) %> } from './<%= dasherize(name) %>';<% } %>
const routes: Routes = [<% if (lazyRoute) { %>{ path: '', component: <%= classify(name) %>Component }<% } %>];
const routes: Routes = [<% if (lazyRoute) { %>{ path: '', component: <%= classify(name) %> }<% } %>];
@NgModule({
imports: [RouterModule.for<%= routingScope %>(routes)],

View File

@ -5,7 +5,7 @@ import { Routes, RouterModule } from '@angular/router';<% } %>
import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing.module';<% } %>
<% if (lazyRouteWithoutRouteModule) { %>
const routes: Routes = [
{ path: '', component: <%= classify(name) %>Component }
{ path: '', component: <%= classify(name) %> }
];<% } %>
@NgModule({

View File

@ -152,9 +152,9 @@ describe('Module Schematic', () => {
jasmine.arrayContaining([
'/projects/bar/src/app/foo/foo.module.ts',
'/projects/bar/src/app/foo/foo-routing.module.ts',
'/projects/bar/src/app/foo/foo.component.ts',
'/projects/bar/src/app/foo/foo.component.ng.html',
'/projects/bar/src/app/foo/foo.component.css',
'/projects/bar/src/app/foo/foo.ts',
'/projects/bar/src/app/foo/foo.ng.html',
'/projects/bar/src/app/foo/foo.css',
]),
);
@ -170,7 +170,7 @@ describe('Module Schematic', () => {
);
expect(fooRoutingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
expect(fooRoutingModuleContent).toMatch(
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/,
/const routes: Routes = \[\r?\n?\s*{ path: '', component: Foo }\r?\n?\s*\];/,
);
});
@ -179,7 +179,7 @@ describe('Module Schematic', () => {
'/projects/bar/src/app/app.module.ts',
`
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppComponent } from './app';
@NgModule({
declarations: [
@ -202,9 +202,9 @@ describe('Module Schematic', () => {
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.ng.html');
expect(files).toContain('/projects/bar/src/app/foo/foo.component.css');
expect(files).toContain('/projects/bar/src/app/foo/foo.ts');
expect(files).toContain('/projects/bar/src/app/foo/foo.ng.html');
expect(files).toContain('/projects/bar/src/app/foo/foo.css');
const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
expect(appModuleContent).toMatch(
@ -214,7 +214,7 @@ describe('Module Schematic', () => {
const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
expect(fooModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
expect(fooModuleContent).toMatch(
/const routes: Routes = \[\r?\n?\s*{ path: '', component: FooComponent }\r?\n?\s*\];/,
/const routes: Routes = \[\r?\n?\s*{ path: '', component: Foo }\r?\n?\s*\];/,
);
});
@ -230,9 +230,9 @@ describe('Module Schematic', () => {
jasmine.arrayContaining([
'/projects/bar/src/app/foo.module.ts',
'/projects/bar/src/app/foo-routing.module.ts',
'/projects/bar/src/app/foo.component.ts',
'/projects/bar/src/app/foo.component.ng.html',
'/projects/bar/src/app/foo.component.css',
'/projects/bar/src/app/foo.ts',
'/projects/bar/src/app/foo.ng.html',
'/projects/bar/src/app/foo.css',
]),
);
@ -271,14 +271,14 @@ describe('Module Schematic', () => {
'/projects/bar/src/app/foo/foo.module.ts',
'/projects/bar/src/app/bar/bar-routing.module.ts',
'/projects/bar/src/app/bar/bar.module.ts',
'/projects/bar/src/app/bar/bar.component.ts',
'/projects/bar/src/app/bar/bar.ts',
]),
);
const barRoutingModuleContent = tree.readContent(
'/projects/bar/src/app/bar/bar-routing.module.ts',
);
expect(barRoutingModuleContent).toContain(`path: '', component: BarComponent `);
expect(barRoutingModuleContent).toContain(`path: '', component: Bar `);
const fooRoutingModuleContent = tree.readContent(
'/projects/bar/src/app/foo/foo-routing.module.ts',

View File

@ -58,7 +58,7 @@ describe('Ng New Schematic', () => {
);
});
it('should should set the prefix in angular.json and in app.component.ts', async () => {
it('should should set the prefix in angular.json and in app.ts', async () => {
const options = { ...defaultOptions, prefix: 'pre' };
const tree = await schematicRunner.runSchematic('ng-new', options);
@ -75,7 +75,7 @@ describe('Ng New Schematic', () => {
const tree = await schematicRunner.runSchematic('ng-new', options);
const moduleContent = tree.readContent('/foo/src/app/app.module.ts');
expect(moduleContent).toMatch(/declarations:\s*\[\s*AppComponent\s*\]/m);
expect(moduleContent).toMatch(/declarations:\s*\[\s*App\s*\]/m);
});
it('createApplication=false should create an empty workspace', async () => {

View File

@ -1,13 +1,13 @@
import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { provideServerRouting } from '@angular/ssr';
import { AppComponent } from './app.component';
import { App } from './app';
import { AppModule } from './app.module';
import { serverRoutes } from './app.routes.server';
@NgModule({
imports: [AppModule, ServerModule],
providers: [provideServerRouting(serverRoutes)],
bootstrap: [AppComponent],
bootstrap: [App],
})
export class AppServerModule {}

View File

@ -1,7 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { App } from './app/app';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = () => bootstrapApplication(App, config);
export default bootstrap;

View File

@ -2,13 +2,13 @@ import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
import { App } from './app';
@NgModule({
imports: [
AppModule,
ServerModule,
],
bootstrap: [AppComponent],
bootstrap: [App],
})
export class AppServerModule {}

View File

@ -1,7 +1,7 @@
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { App } from './app/app';
import { config } from './app/app.config.server';
const bootstrap = () => bootstrapApplication(AppComponent, config);
const bootstrap = () => bootstrapApplication(App, config);
export default bootstrap;

View File

@ -124,7 +124,7 @@ describe('Server Schematic', () => {
const filePath = '/projects/bar/src/main.server.ts';
expect(tree.exists(filePath)).toBeTrue();
const contents = tree.readContent(filePath);
expect(contents).toContain(`bootstrapApplication(AppComponent, config)`);
expect(contents).toContain(`bootstrapApplication(App, config)`);
});
it('should create server app config file', async () => {

View File

@ -39,7 +39,7 @@ function addSnippet(options: WebWorkerOptions): Rule {
.getDir(options.path)
.subfiles // Find all files that start with the same name, are ts files,
// and aren't spec or module files.
.filter((f) => fileRegExp.test(f) && !/(module|spec)\.ts$/.test(f))
.filter((f) => fileRegExp.test(f) && !/(module|spec|config|routes)\.ts$/.test(f))
// Sort alphabetically for consistency.
.sort();

View File

@ -70,7 +70,7 @@ describe('Web Worker Schematic', () => {
it('should add snippet to sibling file', async () => {
const tree = await schematicRunner.runSchematic('web-worker', defaultOptions, appTree);
const appComponent = tree.readContent('/projects/bar/src/app/app.component.ts');
const appComponent = tree.readContent('/projects/bar/src/app/app.ts');
expect(appComponent).toContain(`new Worker(new URL('./${defaultOptions.name}.worker`);
expect(appComponent).toContain('console.log(`page got message: ${data}`)');
});

View File

@ -8,5 +8,5 @@ import { ng } from '../../utils/process';
export default async function () {
await ng('build', '--aot=true', '--configuration=development');
const content = await readFile('dist/test-project/browser/main.js', 'utf-8');
assert.match(content, /AppComponent_Factory/);
assert.match(content, /App_Factory/);
}

View File

@ -7,7 +7,7 @@ import { ngServe } from '../../utils/project';
export default async function () {
const esbuild = getGlobalVariable('argv')['esbuild'];
const validBundleRegEx = esbuild ? /sent to client/ : /Compiled successfully\./;
const lazyBundleRegEx = esbuild ? /chunk-/ : /src_app_lazy_lazy_component_ts\.js/;
const lazyBundleRegEx = esbuild ? /chunk-/ : /src_app_lazy_lazy_ts\.js/;
// Disable HMR to support page reload based rebuild testing.
const port = await ngServe('--no-hmr');
@ -25,7 +25,7 @@ export default async function () {
replaceInFile(
'src/app/app.routes.ts',
'routes: Routes = [];',
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy.component').then(c => c.LazyComponent)}];`,
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy').then(c => c.Lazy)}];`,
),
]);
@ -83,7 +83,7 @@ export default async function () {
await Promise.all([
waitForAnyProcessOutputToMatch(validBundleRegEx),
writeMultipleFiles({
'src/app/app.component.ng.html': '<h1>testingTESTING123</h1>',
'src/app/app.ng.html': '<h1>testingTESTING123</h1>',
}),
]);
@ -99,7 +99,7 @@ export default async function () {
await Promise.all([
waitForAnyProcessOutputToMatch(validBundleRegEx),
writeMultipleFiles({
'src/app/app.component.css': ':host { color: blue; }',
'src/app/app.css': ':host { color: blue; }',
}),
]);

View File

@ -7,7 +7,7 @@ import { updateJsonFile } from '../../../utils/project';
const snapshots = require('../../../ng-snapshot/package.json');
export default async function () {
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>');
await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'app-shell', '--project', 'test-project');
const isSnapshotBuild = getGlobalVariable('argv')['ng-snapshots'];

View File

@ -7,7 +7,7 @@ import { updateJsonFile } from '../../../utils/project';
const snapshots = require('../../../ng-snapshot/package.json');
export default async function () {
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>');
await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'service-worker', '--project', 'test-project');
await ng('generate', 'app-shell', '--project', 'test-project');

View File

@ -33,7 +33,7 @@ export default async function () {
h1 { background: url('/assets/global-img-absolute.svg'); }
h2 { background: url('./assets/global-img-relative.png'); }
`,
'src/app/app.component.css': `
'src/app/app.css': `
h3 { background: url('/assets/component-img-absolute.svg'); }
h4 { background: url('../assets/component-img-relative.png'); }
`,

View File

@ -18,7 +18,7 @@ export default async function () {
'routes: Routes = [];',
`routes: Routes = [{
path: 'lazy',
loadComponent: () => import('./lazy-comp/lazy-comp.component').then(c => c.LazyCompComponent),
loadComponent: () => import('./lazy-comp/lazy-comp').then(c => c.LazyComp),
}];`,
);

View File

@ -29,6 +29,6 @@ export default async function () {
await ng('build', '--configuration=development');
await expectFileToMatch(
'dist/test-project/browser/main.js.map',
'projects/my-lib/src/lib/my-lib.component.ts',
'projects/my-lib/src/lib/my-lib.ts',
);
}

View File

@ -12,6 +12,6 @@ export default async function () {
await ng('build', '--configuration=development');
await expectFileToMatch(
'dist/test-project/browser/main.js.map',
'projects/my-lib/src/lib/my-lib.component.ts',
'projects/my-lib/src/lib/my-lib.ts',
);
}

View File

@ -11,7 +11,7 @@ export default async function () {
// Add an unused class as part of the public api.
await appendToFile(
'projects/my-lib/src/lib/my-lib.component.ts',
'projects/my-lib/src/lib/my-lib.ts',
`
function something() {
return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {

View File

@ -6,16 +6,16 @@ export async function libraryConsumptionSetup(): Promise<void> {
// Force an external template
await writeMultipleFiles({
'projects/my-lib/src/lib/my-lib.component.ng.html': `<p>my-lib works!</p>`,
'projects/my-lib/src/lib/my-lib.component.ts': `import { Component } from '@angular/core';
'projects/my-lib/src/lib/my-lib.ng.html': `<p>my-lib works!</p>`,
'projects/my-lib/src/lib/my-lib.ts': `import { Component } from '@angular/core';
@Component({
standalone: true,
selector: 'lib-my-lib',
templateUrl: './my-lib.component.ng.html',
templateUrl: './my-lib.ng.html',
})
export class MyLibComponent {}`,
'./src/app/app.component.ts': `
'./src/app/app.ts': `
import { Component } from '@angular/core';
import { MyLibService, MyLibComponent } from 'my-lib';
@ -25,7 +25,7 @@ export async function libraryConsumptionSetup(): Promise<void> {
template: '<lib-my-lib></lib-my-lib>',
imports: [MyLibComponent],
})
export class AppComponent {
export class App {
title = 'test-project';
constructor(myLibService: MyLibService) {

View File

@ -50,25 +50,25 @@ export default async function () {
`
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { OneComponent } from './one/one.component';
import { TwoChildOneComponent } from './two-child-one/two-child-one.component';
import { TwoChildTwoComponent } from './two-child-two/two-child-two.component';
import { One} from './one/one';
import { TwoChildOne } from './two-child-one/two-child-one';
import { TwoChildTwo } from './two-child-two/two-child-two';
const routes: Routes = [
{
path: '',
component: OneComponent,
component: One,
},
{
path: 'two',
children: [
{
path: 'two-child-one',
component: TwoChildOneComponent,
component: TwoChildOne,
},
{
path: 'two-child-two',
component: TwoChildTwoComponent,
component: TwoChildTwo,
},
],
},

View File

@ -20,25 +20,25 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { OneComponent } from './one/one.component';
import { TwoChildOneComponent } from './two-child-one/two-child-one.component';
import { TwoChildTwoComponent } from './two-child-two/two-child-two.component';
import { One } from './one/one';
import { TwoChildOne } from './two-child-one/two-child-one';
import { TwoChildTwo } from './two-child-two/two-child-two';
export const routes: Routes = [
{
path: '',
component: OneComponent,
component: One,
},
{
path: 'two',
children: [
{
path: 'two-child-one',
component: TwoChildOneComponent,
component: TwoChildOne,
},
{
path: 'two-child-two',
component: TwoChildTwoComponent,
component: TwoChildTwo,
},
],
},
@ -47,17 +47,17 @@ export default async function () {
children: [
{
path: '',
loadComponent: () => import('./lazy-one/lazy-one.component').then(c => c.LazyOneComponent),
loadComponent: () => import('./lazy-one/lazy-one').then(c => c.LazyOne),
},
{
path: 'lazy-one-child',
loadComponent: () => import('./lazy-one-child/lazy-one-child.component').then(c => c.LazyOneChildComponent),
loadComponent: () => import('./lazy-one-child/lazy-one-child').then(c => c.LazyOneChild),
},
],
},
{
path: 'lazy-two',
loadComponent: () => import('./lazy-two/lazy-two.component').then(c => c.LazyTwoComponent),
loadComponent: () => import('./lazy-two/lazy-two').then(c => c.LazyTwo),
},
];
`,

View File

@ -19,7 +19,7 @@ export default async function () {
await installWorkspacePackages();
await writeMultipleFiles({
'src/app/app.component.ts': `
'src/app/app.ts': `
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
@ -28,10 +28,10 @@ export default async function () {
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: './app.component.ng.html',
styleUrls: ['./app.component.css']
templateUrl: './app.ng.html',
styleUrls: ['./app.css']
})
export class AppComponent {
export class App {
title = 'test-ssr';
constructor() {
@ -48,6 +48,6 @@ export default async function () {
message,
// When babel is used it will add names to the sourcemap and `constructor` will be used in the stack trace.
// This will currently only happen if AOT and script optimizations are set which enables advanced optimizations.
/window is not defined[.\s\S]*(?:constructor|_AppComponent) \(.*app\.component\.ts\:\d+:\d+\)/,
/window is not defined[.\s\S]*(?:constructor|_App) \(.*app\.ts\:\d+:\d+\)/,
);
}

View File

@ -23,7 +23,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import {HomeComponent} from './home/home.component';
import {Home} from './home/home';
import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
@ -31,7 +31,7 @@ export default async function () {
providers: [
provideRouter([{
path: '',
component: HomeComponent,
component: Home,
}]),
provideClientHydration(),
provideHttpClient(withFetch()),
@ -44,7 +44,7 @@ export default async function () {
'public/media with-space.json': JSON.stringify({ dataFromAssetsWithSpace: true }),
// Update component to do an HTTP call to asset.
'src/app/app.component.ts': `
'src/app/app.ts': `
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
@ -60,7 +60,7 @@ export default async function () {
<router-outlet></router-outlet>
\`,
})
export class AppComponent {
export class App {
data: any;
dataWithSpace: any;

View File

@ -31,14 +31,14 @@ export default async function () {
}
await writeMultipleFiles({
'src/app/app.component.css': `div { color: #000 }`,
'src/app/app.css': `div { color: #000 }`,
'src/styles.css': `* { color: #000 }`,
'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { App } from './app/app';
import { appConfig } from './app/app.config';
(window as any)['doBootstrap'] = () => {
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
};
`,
'src/index.html': `

View File

@ -66,7 +66,7 @@ export default async function () {
}
await writeMultipleFiles({
'projects/test-project-two/src/app/app.component.css': `div { color: #000 }`,
'projects/test-project-two/src/app/app.css': `div { color: #000 }`,
'projects/test-project-two/src/styles.css': `* { color: #000 }`,
'projects/test-project-two/src/main.ts': `
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

View File

@ -32,14 +32,14 @@ export default async function () {
await installWorkspacePackages();
await writeMultipleFiles({
'src/app/app.component.css': `div { color: #000 }`,
'src/app/app.css': `div { color: #000 }`,
'src/styles.css': `* { color: #000 }`,
'src/main.ts': `import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { App } from './app/app';
import { appConfig } from './app/app.config';
(window as any)['doBootstrap'] = () => {
bootstrapApplication(AppComponent, appConfig).catch((err) => console.error(err));
bootstrapApplication(App, appConfig).catch((err) => console.error(err));
};
`,
'e2e/src/app.e2e-spec.ts': `

View File

@ -28,22 +28,22 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsrComponent } from './ssr/ssr.component';
import { SsgComponent } from './ssg/ssg.component';
import { Home } from './home/home';
import { Ssr } from './ssr/ssr';
import { Ssg } from './ssg/ssg';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: 'ssr',
component: SsrComponent,
component: Ssr,
},
];
`,

View File

@ -53,22 +53,22 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsrComponent } from './ssr/ssr.component';
import { SsgComponent } from './ssg/ssg.component';
import { Home } from './home/home';
import { Ssr } from './ssr/ssr';
import { Ssg } from './ssg/ssg';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: 'ssr',
component: SsrComponent,
component: Ssr,
},
];
`,

View File

@ -28,22 +28,22 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsrComponent } from './ssr/ssr.component';
import { SsgComponent } from './ssg/ssg.component';
import { Home } from './home/home';
import { Ssr } from './ssr/ssr';
import { Ssg } from './ssg/ssg';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: 'ssr',
component: SsrComponent,
component: Ssr,
},
];
`,

View File

@ -27,26 +27,26 @@ export default async function () {
await installPackage('h3@1');
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsrComponent } from './ssr/ssr.component';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component';
import { Home } from './home/home';
import { Ssr } from './ssr/ssr';
import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssr',
component: SsrComponent,
component: Ssr,
},
{
path: 'ssg/:id',
component: SsgWithParamsComponent,
component: SsgWithParams,
},
];
`,

View File

@ -21,38 +21,38 @@ export default async function () {
await installWorkspacePackages();
// Test scenario to verify that the content length, including \r\n, is accurate
await replaceInFile('src/app/app.component.ts', "title = '", "title = 'Title\\r\\n");
await replaceInFile('src/app/app.ts', "title = '", "title = 'Title\\r\\n");
// Ensure text has been updated.
assert.match(await readFile('src/app/app.component.ts'), /title = 'Title/);
assert.match(await readFile('src/app/app.ts'), /title = 'Title/);
// Add routes
await writeFile(
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { CsrComponent } from './csr/csr.component';
import { SsrComponent } from './ssr/ssr.component';
import { SsgComponent } from './ssg/ssg.component';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component';
import { Home } from './home/home';
import { Csr } from './csr/csr';
import { Ssr } from './ssr/ssr';
import { Ssg } from './ssg/ssg';
import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: 'ssr',
component: SsrComponent,
component: Ssr,
},
{
path: 'csr',
component: CsrComponent,
component: Csr,
},
{
path: 'redirect',
@ -60,7 +60,7 @@ export default async function () {
},
{
path: 'ssg/:id',
component: SsgWithParamsComponent,
component: SsgWithParams,
},
];
`,

View File

@ -21,7 +21,7 @@ export default async function () {
// Add asset
'public/media.json': JSON.stringify({ dataFromAssets: true }),
// Update component to do an HTTP call to asset and API.
'src/app/app.component.ts': `
'src/app/app.ts': `
import { Component, inject } from '@angular/core';
import { JsonPipe } from '@angular/common';
import { RouterOutlet } from '@angular/router';
@ -37,7 +37,7 @@ export default async function () {
<router-outlet></router-outlet>
\`,
})
export class AppComponent {
export class App {
assetsData: any;
apiData: any;
@ -59,7 +59,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
@ -67,7 +67,7 @@ export default async function () {
providers: [
provideRouter([{
path: 'home',
component: HomeComponent,
component: Home,
}]),
provideClientHydration(),
provideHttpClient(withFetch()),

View File

@ -28,21 +28,21 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsgComponent } from './ssg/ssg.component';
import { Home } from './home/home';
import { Ssg } from './ssg/ssg';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: '**',
component: HomeComponent,
component: Home,
},
];
`,

View File

@ -30,18 +30,18 @@ export default async function () {
'src/app/app.routes.ts',
`
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { SsgComponent } from './ssg/ssg.component';
import { SsgWithParamsComponent } from './ssg-with-params/ssg-with-params.component';
import { Home } from './home/home';
import { Ssg } from './ssg/ssg';
import { SsgWithParams } from './ssg-with-params/ssg-with-params';
export const routes: Routes = [
{
path: '',
component: HomeComponent,
component: Home,
},
{
path: 'ssg',
component: SsgComponent,
component: Ssg,
},
{
path: 'ssg-redirect',
@ -49,11 +49,11 @@ export default async function () {
},
{
path: 'ssg/:id',
component: SsgWithParamsComponent,
component: SsgWithParams,
},
{
path: '**',
component: HomeComponent,
component: Home,
},
];
`,

View File

@ -31,7 +31,7 @@ export default async function () {
export const routes: Routes = [
{
path: '',
loadComponent: () => import('./home/home.component').then(c => c.HomeComponent),
loadComponent: () => import('./home/home').then(c => c.Home),
},
{
path: 'ssg',
@ -39,11 +39,11 @@ export default async function () {
},
{
path: 'ssr',
loadComponent: () => import('./ssr/ssr.component').then(c => c.SsrComponent),
loadComponent: () => import('./ssr/ssr').then(c => c.Ssr),
},
{
path: 'csr',
loadComponent: () => import('./csr/csr.component').then(c => c.CsrComponent),
loadComponent: () => import('./csr/csr').then(c => c.Csr),
},
];
`,
@ -72,21 +72,21 @@ export default async function () {
export const routes: Routes = [
{
path: '',
loadComponent: () => import('./ssg/ssg.component').then(c => c.SsgComponent),
loadComponent: () => import('./ssg-component/ssg-component').then(c => c.SsgComponent),
},
{
path: 'one',
loadComponent: () => import('./ssg-one/ssg-one.component').then(c => c.SsgOneComponent),
loadComponent: () => import('./ssg-one/ssg-one').then(c => c.SsgOne),
},
{
path: 'two',
loadComponent: () => import('./ssg-two/ssg-two.component').then(c => c.SsgTwoComponent),
loadComponent: () => import('./ssg-two/ssg-two').then(c => c.SsgTwo),
},
];`,
});
// Generate components for the above routes
const componentNames: string[] = ['home', 'ssg', 'csr', 'ssr', 'ssg-one', 'ssg-two'];
const componentNames: string[] = ['home', 'ssg-component', 'csr', 'ssr', 'ssg-one', 'ssg-two'];
for (const componentName of componentNames) {
await silentNg('generate', 'component', componentName);
@ -95,18 +95,18 @@ export default async function () {
// Add a cross-dependency
await Promise.all([
replaceInFile(
'src/app/ssg-one/ssg-one.component.ts',
`OneComponent {`,
`OneComponent {
'src/app/ssg-one/ssg-one.ts',
`One {`,
`One {
async ngOnInit() {
await import('../cross-dep');
}
`,
),
replaceInFile(
'src/app/ssg-two/ssg-two.component.ts',
`TwoComponent {`,
`TwoComponent {
'src/app/ssg-two/ssg-two.ts',
`Two {`,
`Two {
async ngOnInit() {
await import('../cross-dep');
}
@ -129,58 +129,39 @@ const RESPONSE_EXPECTS: Record<
}
> = {
'/': {
matches: [/<link rel="modulepreload" href="(home\.component-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/ssg\.component/, /ssr\.component/, /csr\.component/, /cross-dep-/],
matches: [/<link rel="modulepreload" href="(home-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/ssg\-component/, /ssr/, /csr/, /cross-dep-/],
},
'/ssg': {
matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg\.component-[a-zA-Z0-9]{8}\.js)">/,
],
notMatches: [
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-one\.component/,
/ssg-two\.component/,
/cross-dep-/,
/<link rel="modulepreload" href="(ssg-component-[a-zA-Z0-9]{8}\.js)">/,
],
notMatches: [/home/, /ssr/, /csr/, /ssg-one/, /ssg-two/, /cross-dep-/],
},
'/ssg/one': {
matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-one\.component-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-one-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/,
],
notMatches: [
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-two\.component/,
/ssg\.component/,
],
notMatches: [/home/, /ssr/, /csr/, /ssg-two/, /ssg\-component/],
},
'/ssg/two': {
matches: [
/<link rel="modulepreload" href="(ssg\.routes-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-two\.component-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(ssg-two-[a-zA-Z0-9]{8}\.js)">/,
/<link rel="modulepreload" href="(cross-dep-[a-zA-Z0-9]{8}\.js)">/,
],
notMatches: [
/home\.component/,
/ssr\.component/,
/csr\.component/,
/ssg-one\.component/,
/ssg\.component/,
],
notMatches: [/home/, /ssr/, /csr/, /ssg-one/, /ssg\-component/],
},
'/ssr': {
matches: [/<link rel="modulepreload" href="(ssr\.component-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home\.component/, /ssg\.component/, /csr\.component/],
matches: [/<link rel="modulepreload" href="(ssr-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home/, /ssg\-component/, /csr/],
},
'/csr': {
matches: [/<link rel="modulepreload" href="(csr\.component-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home\.component/, /ssg\.component/, /ssr\.component/, /cross-dep-/],
matches: [/<link rel="modulepreload" href="(csr-[a-zA-Z0-9]{8}\.js)">/],
notMatches: [/home/, /ssg\-component/, /ssr/, /cross-dep-/],
},
};

View File

@ -10,7 +10,7 @@ export default async function () {
@import 'variables';
h1 { color: $primary-color; }
`,
'src/app/app.component.scss': `
'src/app/app.scss': `
@import 'variables';
h2 { color: $primary-color; }
`,
@ -19,16 +19,16 @@ export default async function () {
@import 'variables';
h5 { color: @primary-color; }
`,
'src/app/app.component.less': `
'src/app/app.less': `
@import 'variables';
h6 { color: @primary-color; }
`,
});
await replaceInFile(
'src/app/app.component.ts',
`styleUrl: './app.component.css\'`,
`styleUrls: ['./app.component.scss', './app.component.less']`,
'src/app/app.ts',
`styleUrl: './app.css\'`,
`styleUrls: ['./app.scss', './app.less']`,
);
await updateJsonFile('angular.json', (workspaceJson) => {

View File

@ -17,7 +17,7 @@ export default function () {
body { background-color: blue; }
`,
'src/imported-styles.less': 'p { background-color: red; }',
'src/app/app.component.less': `
'src/app/app.less': `
.outer {
.inner {
background: #fff;
@ -25,16 +25,14 @@ export default function () {
}
`,
})
.then(() => deleteFile('src/app/app.component.css'))
.then(() => deleteFile('src/app/app.css'))
.then(() =>
updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.less' }];
}),
)
.then(() =>
replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.less'),
)
.then(() => replaceInFile('src/app/app.ts', './app.css', './app.less'))
.then(() => ng('build', '--source-map', '--configuration=development'))
.then(() =>
expectFileToMatch(

View File

@ -15,7 +15,7 @@ export default async function () {
body { background-color: blue; }
`,
'src/imported-styles.scss': 'p { background-color: red; }',
'src/app/app.component.scss': `
'src/app/app.scss': `
.outer {
.inner {
background: #fff;
@ -24,12 +24,12 @@ export default async function () {
`,
});
await deleteFile('src/app/app.component.css');
await deleteFile('src/app/app.css');
await updateJsonFile('angular.json', (workspaceJson) => {
const appArchitect = workspaceJson.projects['test-project'].architect;
appArchitect.build.options.styles = [{ input: 'src/styles.scss' }];
});
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss');
await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--configuration=development');

View File

@ -19,7 +19,7 @@ export default async function () {
p
background-color: red
`,
'src/app/app.component.sass': `
'src/app/app.sass': `
.outer
.inner
background: #fff
@ -31,8 +31,8 @@ export default async function () {
appArchitect.build.options.styles = [{ input: 'src/styles.sass' }];
});
await deleteFile('src/app/app.component.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.sass');
await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.ts', './app.css', './app.sass');
await ng('build', '--source-map', '--configuration=development');

View File

@ -16,7 +16,7 @@ export default async function () {
@include button.core-styles;
`,
'src/app/app.component.scss': `
'src/app/app.scss': `
@use '@material/button/button';
@include button.core-styles;
@ -28,8 +28,8 @@ export default async function () {
appArchitect.build.options.styles = ['src/styles.scss'];
});
await deleteFile('src/app/app.component.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss');
await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--configuration=development');
}

View File

@ -15,7 +15,7 @@ export default async function () {
body { background-color: blue; }
`,
'src/imported-styles.scss': 'p { background-color: red; }',
'src/app/app.component.scss': `
'src/app/app.scss': `
.outer {
.inner {
background: #fff;
@ -29,8 +29,8 @@ export default async function () {
appArchitect.build.options.styles = [{ input: 'src/styles.scss' }];
});
await deleteFile('src/app/app.component.css');
await replaceInFile('src/app/app.component.ts', './app.component.css', './app.component.scss');
await deleteFile('src/app/app.css');
await replaceInFile('src/app/app.ts', './app.css', './app.scss');
await ng('build', '--source-map', '--configuration=development');

View File

@ -12,7 +12,7 @@ export default async function () {
await silentExec('npx', 'tailwindcss@2', 'init');
// Add Tailwind directives to a component style
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components;');
await writeFile('src/app/app.css', '@tailwind base; @tailwind components;');
// Add Tailwind directives to a global style
await writeFile('src/styles.css', '@tailwind base; @tailwind components;');

View File

@ -16,7 +16,7 @@ export default async function () {
await silentExec('npx', 'tailwindcss@3', 'init');
// Add Tailwind directives to a component style
await writeFile('src/app/app.component.css', '@tailwind base; @tailwind components;');
await writeFile('src/app/app.css', '@tailwind base; @tailwind components;');
// Add Tailwind directives to a global style
await writeFile(

View File

@ -19,7 +19,7 @@ export default async function () {
'src/app/shared/index.ts': `export * from './meaning'`,
});
await replaceInFile('src/main.ts', './app/app.component', '@root/app/app.component');
await replaceInFile('src/main.ts', './app/app', '@root/app/app');
await ng('build', '--configuration=development');
await updateTsConfig((json) => {
@ -27,7 +27,7 @@ export default async function () {
});
await appendToFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
import { meaning } from 'app/shared/meaning';
import { meaning as meaning2 } from '@shared';

View File

@ -49,16 +49,12 @@ export default async function () {
// Use WASM file in project
await prependToFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
import { multiply, subtract1 } from './multiply.wasm';
`,
);
await replaceInFile(
'src/app/app.component.ts',
"'test-project'",
'multiply(4, 5) + subtract1(88)',
);
await replaceInFile('src/app/app.ts', "'test-project'", 'multiply(4, 5) + subtract1(88)');
// Remove Zone.js from polyfills and make zoneless
await updateJsonFile('angular.json', (json) => {

View File

@ -16,7 +16,7 @@ export default async function () {
const useWebpackBuilder = !getGlobalVariable('argv')['esbuild'];
const workerPath = 'src/app/app.worker.ts';
const snippetPath = 'src/app/app.component.ts';
const snippetPath = 'src/app/app.ts';
const projectTsConfig = 'tsconfig.json';
const workerTsConfig = 'tsconfig.worker.json';
@ -52,7 +52,7 @@ export default async function () {
// console.warn has to be used because chrome only captures warnings and errors by default
// https://github.com/angular/protractor/issues/2207
await replaceInFile('src/app/app.component.ts', 'console.log', 'console.warn');
await replaceInFile('src/app/app.ts', 'console.log', 'console.warn');
await writeFile(
'e2e/app.e2e-spec.ts',

View File

@ -27,7 +27,7 @@ export default async function () {
import { ApplicationConfig } from '@angular/core';
import { provideRouter } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
import { provideClientHydration } from '@angular/platform-browser';
import { provideHttpClient, withFetch } from '@angular/common/http';
@ -35,7 +35,7 @@ export default async function () {
providers: [
provideRouter([{
path: '',
component: HomeComponent,
component: Home,
}]),
provideClientHydration(),
provideHttpClient(withFetch()),
@ -45,7 +45,7 @@ export default async function () {
// Add asset
'public/media.json': JSON.stringify({ dataFromAssets: true }),
// Update component to do an HTTP call to asset.
'src/app/app.component.ts': `
'src/app/app.ts': `
import { Component, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
@ -60,7 +60,7 @@ export default async function () {
<router-outlet></router-outlet>
\`,
})
export class AppComponent {
export class App {
data: any;
constructor() {
const http = inject(HttpClient);

View File

@ -9,10 +9,10 @@ export default function () {
return (
ng('generate', 'component', 'test-component')
.then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css')))
.then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -19,10 +19,10 @@ export default async function () {
// Ensure component is created in the correct location relative to the workspace root
const componentDirectory = join(childDirectory, 'test-component');
await expectFileToExist(join(componentDirectory, 'test-component.component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.component.css'));
await expectFileToExist(join(componentDirectory, 'test-component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.css'));
// Ensure unit test execute and pass
await ng('test', '--watch=false');

View File

@ -16,10 +16,10 @@ export default function () {
)
.then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(appDir))
.then(() => expectFileToExist(join(appDir, 'test-component.component.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.spec.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.ng.html')))
.then(() => expectFileToExist(join(appDir, 'test-component.component.css')))
.then(() => expectFileToExist(join(appDir, 'test-component.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(appDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(appDir, 'test-component.css')))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -18,14 +18,12 @@ export default function () {
)
.then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() =>
expectToFail(() =>
expectFileToExist(join(componentDir, 'test-component.component.ng.html')),
),
expectToFail(() => expectFileToExist(join(componentDir, 'test-component.ng.html'))),
)
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css')))
.then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -17,10 +17,10 @@ export default function () {
)
.then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(componentDir))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.component.css')))
.then(() => expectFileToExist(join(componentDir, 'test-component.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(componentDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(componentDir, 'test-component.css')))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -14,19 +14,19 @@ export default async function () {
await ng('generate', 'component', `${upperDirs}/test-component`);
// Ensure component is created in the correct location relative to the workspace root
await expectFileToExist(join(componentDirectory, 'test-component.component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.component.css'));
await expectFileToExist(join(componentDirectory, 'test-component.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.spec.ts'));
await expectFileToExist(join(componentDirectory, 'test-component.ng.html'));
await expectFileToExist(join(componentDirectory, 'test-component.css'));
// Generate another component
await ng('generate', 'component', `${upperDirs}/Test-Component-Two`);
// Ensure component is created in the correct location relative to the workspace root
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.spec.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.ng.html'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.component.css'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.spec.ts'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.ng.html'));
await expectFileToExist(join(componentTwoDirectory, 'test-component-two.css'));
// Ensure unit test execute and pass
await ng('test', '--watch=false');

View File

@ -17,11 +17,9 @@ export default function () {
}),
)
.then(() => ng('generate', 'component', 'test-component'))
.then(() =>
expectFileToMatch(join(testCompDir, 'test-component.component.ts'), /selector: 'pre-/),
)
.then(() => expectFileToMatch(join(testCompDir, 'test-component.ts'), /selector: 'pre-/))
.then(() => ng('g', 'c', 'alias'))
.then(() => expectFileToMatch(join(aliasCompDir, 'alias.component.ts'), /selector: 'pre-/))
.then(() => expectFileToMatch(join(aliasCompDir, 'alias.ts'), /selector: 'pre-/))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -16,10 +16,10 @@ export default function () {
)
.then(() => ng('generate', 'component', 'test-component'))
.then(() => expectFileToExist(compDir))
.then(() => expectFileToExist(join(compDir, 'test-component.component.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.spec.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.ng.html')))
.then(() => expectFileToExist(join(compDir, 'test-component.component.css')))
.then(() => expectFileToExist(join(compDir, 'test-component.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.spec.ts')))
.then(() => expectFileToExist(join(compDir, 'test-component.ng.html')))
.then(() => expectFileToExist(join(compDir, 'test-component.css')))
// Try to run the unit tests.
.then(() => ng('test', '--watch=false'))

View File

@ -12,8 +12,8 @@ export default async function () {
// Generate component in application to verify that it's minimal
const { stdout } = await ng('generate', 'component', 'foo');
if (!stdout.includes('foo.component.scss')) {
throw new Error('Expected "foo.component.scss" to exist.');
if (!stdout.includes('foo.scss')) {
throw new Error('Expected "foo.scss" to exist.');
}
// Generate another project with different settings
@ -23,6 +23,7 @@ export default async function () {
config.projects['test-project-two'].schematics = {
'@schematics/angular:component': {
style: 'less',
type: 'Component',
},
};
});

View File

@ -15,24 +15,21 @@ export default async function () {
// Setup an i18n enabled component
await ng('generate', 'component', 'i18n-test');
await writeFile(
join('src/app/i18n-test', 'i18n-test.component.ng.html'),
'<p i18n>Hello world</p>',
);
await writeFile(join('src/app/i18n-test', 'i18n-test.ng.html'), '<p i18n>Hello world</p>');
await writeFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
import { Component } from '@angular/core';
import { I18nTestComponent } from './i18n-test/i18n-test.component';
import { I18nTest } from './i18n-test/i18n-test';
@Component({
standalone: true,
selector: 'app-root',
imports: [I18nTestComponent],
imports: [I18nTest],
template: '<app-i18n-test />'
})
export class AppComponent {}
export class App {}
`,
);

View File

@ -7,24 +7,17 @@ import { readNgVersion } from '../../utils/version';
export default async function () {
// Setup a library
await ng('generate', 'library', 'i18n-lib-test');
await replaceInFile(
'projects/i18n-lib-test/src/lib/i18n-lib-test.component.ts',
'<p>',
'<p i18n>',
);
await replaceInFile('projects/i18n-lib-test/src/lib/i18n-lib-test.ts', '<p>', '<p i18n>');
// Build library
await ng('build', 'i18n-lib-test', '--configuration=development');
// Consume library in application
await replaceInFile('src/app/app.component.ts', 'imports: [', 'imports: [I18nLibTestComponent,');
await prependToFile(
'src/app/app.component.ts',
`import { I18nLibTestComponent } from 'i18n-lib-test';`,
);
await replaceInFile('src/app/app.ts', 'imports: [', 'imports: [I18nLibTest,');
await prependToFile('src/app/app.ts', `import { I18nLibTest } from 'i18n-lib-test';`);
await writeFile(
'src/app/app.component.ng.html',
'src/app/app.ng.html',
`
<p i18n>Hello world</p>
<lib-i18n-lib-test></lib-i18n-lib-test>
@ -42,11 +35,8 @@ export default async function () {
await ng('extract-i18n');
await expectFileToMatch('messages.xlf', 'Hello world');
await expectFileToMatch('messages.xlf', 'i18n-lib-test works!');
await expectFileToMatch('messages.xlf', 'src/app/app.component.ng.html');
await expectFileToMatch(
'messages.xlf',
'projects/i18n-lib-test/src/lib/i18n-lib-test.component.ts',
);
await expectFileToMatch('messages.xlf', 'src/app/app.ng.html');
await expectFileToMatch('messages.xlf', 'projects/i18n-lib-test/src/lib/i18n-lib-test.ts');
await uninstallPackage('@angular/localize');
}

View File

@ -9,24 +9,21 @@ import { readNgVersion } from '../../utils/version';
export default async function () {
// Setup an i18n enabled component
await ng('generate', 'component', 'i18n-test');
await writeFile(
join('src/app/i18n-test', 'i18n-test.component.ng.html'),
'<p i18n>Hello world</p>',
);
await writeFile(join('src/app/i18n-test', 'i18n-test.ng.html'), '<p i18n>Hello world</p>');
// Actually use the generated component to ensure it is present in the application output
await writeFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
import { Component } from '@angular/core';
import { I18nTestComponent } from './i18n-test/i18n-test.component';
import { I18nTest } from './i18n-test/i18n-test';
@Component({
standalone: true,
selector: 'app-root',
imports: [I18nTestComponent],
imports: [I18nTest],
template: '<app-i18n-test />'
})
export class AppComponent {}
export class App {}
`,
);

View File

@ -17,7 +17,7 @@ export default async function () {
: readNgVersion();
});
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>');
await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
// Add app-shell and service-worker
await silentNg('generate', 'app-shell');

View File

@ -23,7 +23,7 @@ export default async function () {
: readNgVersion();
});
await appendToFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>');
await appendToFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
await ng('generate', 'app-shell', '--project', 'test-project');
if (isSnapshotBuild) {
@ -62,7 +62,7 @@ export default async function () {
});
await writeFile(
'src/app/app-shell/app-shell.component.ng.html',
'src/app/app-shell/app-shell.ng.html',
'<h1 i18n="An introduction header for this sample">Hello i18n!</h1>',
);
@ -70,7 +70,7 @@ export default async function () {
// Extraction of i18n only works on browser targets.
// Let's add the same translation that there is in the app-shell
await writeFile(
'src/app/app.component.ng.html',
'src/app/app.ng.html',
'<h1 i18n="An introduction header for this sample">Hello i18n!</h1>',
);
@ -79,9 +79,9 @@ export default async function () {
await expectFileToMatch('src/locale/messages.xlf', `source-language="en-US"`);
await expectFileToMatch('src/locale/messages.xlf', `An introduction header for this sample`);
// Clean up app.component.ng.html so that we can easily
// Clean up app.ng.html so that we can easily
// find the translation text
await writeFile('src/app/app.component.ng.html', '<router-outlet></router-outlet>');
await writeFile('src/app/app.ng.html', '<router-outlet></router-outlet>');
for (const { lang, translation } of langTranslations) {
if (lang != 'en-US') {

View File

@ -98,7 +98,7 @@ export const baseHrefs: { [l: string]: string } = {
export async function setupI18nConfig() {
// Add component with i18n content, both translations and localeData (plural, dates).
await writeFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
import { Component, Inject, LOCALE_ID } from '@angular/core';
import { DatePipe } from '@angular/common';
@ -108,9 +108,9 @@ export async function setupI18nConfig() {
selector: 'app-root',
imports: [DatePipe, RouterOutlet],
standalone: true,
templateUrl: './app.component.ng.html'
templateUrl: './app.ng.html'
})
export class AppComponent {
export class App {
constructor(@Inject(LOCALE_ID) public locale: string) { }
title = 'i18n';
jan = new Date(2000, 0, 1);
@ -119,7 +119,7 @@ export async function setupI18nConfig() {
`,
);
await writeFile(
`src/app/app.component.ng.html`,
`src/app/app.ng.html`,
`
<p id="hello" i18n="An introduction header for this sample">Hello {{ title }}! </p>
<p id="locale">{{ locale }}</p>
@ -140,7 +140,7 @@ export async function setupI18nConfig() {
<trans-unit id="4286451273117902052" datatype="html">
<source>Hello <x id="INTERPOLATION" equiv-text="{{ title }}"/>! </source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context>
<context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">2,3</context>
</context-group>
<note priority="1" from="description">An introduction header for this sample</note>
@ -148,14 +148,14 @@ export async function setupI18nConfig() {
<trans-unit id="4606963464835766483" datatype="html">
<source>Updated <x id="ICU" equiv-text="{minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}" xid="1887283401472369100"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context>
<context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">5,6</context>
</context-group>
</trans-unit>
<trans-unit id="2002272803511843863" datatype="html">
<source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION"/> minutes ago}}</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ng.html</context>
<context context-type="sourcefile">src/app/app.ng.html</context>
<context context-type="linenumber">5,6</context>
</context-group>
</trans-unit>
@ -168,7 +168,7 @@ export async function setupI18nConfig() {
// ng serve support: https://github.com/angular/angular-cli/issues/16248
await writeFile('src/app/dynamic.ts', `export const abc = 5;`);
await appendToFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
(async () => { await import('./dynamic'); })();
`,

View File

@ -11,7 +11,7 @@ export default async function () {
}
// Workaround for https://github.com/angular/angular/issues/32192
await replaceInFile('src/app/app.component.ng.html', /class="material-icons"/g, '');
await replaceInFile('src/app/app.ng.html', /class="material-icons"/g, '');
await ng('build');

View File

@ -15,5 +15,5 @@ export default async function () {
throw new Error(`Expected stderr to contain: "${warningMatch}".`);
}
await expectFileToExist('src/app/test-component/test-component.component.sass');
await expectFileToExist('src/app/test-component/test-component.sass');
}

View File

@ -5,12 +5,12 @@ export default async function () {
await ng('generate', 'service', 'user');
// Update the application to use the new service
await prependToFile('src/app/app.component.ts', "import { UserService } from './user.service';");
await prependToFile('src/app/app.ts', "import { UserService } from './user.service';");
await replaceInFile(
'src/app/app.component.ts',
'export class AppComponent {',
'export class AppComponent {\n constructor(user: UserService) {}',
'src/app/app.ts',
'export class App {',
'export class App {\n constructor(user: UserService) {}',
);
// Execute the application's tests with emitDecoratorMetadata disabled (default)

View File

@ -5,25 +5,25 @@ import { expectToFail } from '../../utils/utils';
export default async function () {
// Update the application to use a forward reference
await replaceInFile(
'src/app/app.component.ts',
'src/app/app.ts',
"import { Component } from '@angular/core';",
"import { Component, Inject, Injectable, forwardRef } from '@angular/core';",
);
await appendToFile('src/app/app.component.ts', '\n@Injectable() export class Lock { }\n');
await appendToFile('src/app/app.ts', '\n@Injectable() export class Lock { }\n');
await replaceInFile(
'src/app/app.component.ts',
'export class AppComponent {',
'export class AppComponent {\n constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {}',
'src/app/app.ts',
'export class App {',
'export class App {\n constructor(@Inject(forwardRef(() => Lock)) lock: Lock) {}',
);
// Update the application's unit tests to include the new injectable
await replaceInFile(
'src/app/app.component.spec.ts',
"import { AppComponent } from './app.component';",
"import { AppComponent, Lock } from './app.component';",
'src/app/app.spec.ts',
"import { App } from './app';",
"import { App, Lock } from './app';",
);
await replaceInFile(
'src/app/app.component.spec.ts',
'src/app/app.spec.ts',
'TestBed.configureTestingModule({',
'TestBed.configureTestingModule({ providers: [Lock],',
);

View File

@ -16,7 +16,7 @@ export default async function () {
await replaceInFile(
'src/app/app.routes.ts',
'routes: Routes = [];',
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy.component').then(c => c.LazyComponent)}];`,
`routes: Routes = [{path: 'lazy', loadComponent: () => import('./lazy/lazy').then(c => c.Lazy)}];`,
);
// Add lazy route e2e

View File

@ -5,7 +5,7 @@ import { expectToFail } from '../../utils/utils';
export default async function () {
// This test is already in build-angular, but that doesn't run on Windows.
await silentNg('test', '--no-watch', '--code-coverage');
await expectFileToExist('coverage/test-project/app.component.ts.html');
await expectFileToExist('coverage/test-project/app.ts.html');
// Delete coverage directory
await rimraf('coverage');
@ -13,10 +13,10 @@ export default async function () {
'test',
'--no-watch',
'--code-coverage',
`--code-coverage-exclude='src/**/app.component.ts'`,
`--code-coverage-exclude='src/**/app.ts'`,
);
// Doesn't include excluded.
await expectFileToExist('coverage/test-project/index.html');
await expectToFail(() => expectFileToExist('coverage/test-project/app.component.ts.html'));
await expectToFail(() => expectFileToExist('coverage/test-project/app.ts.html'));
}

View File

@ -6,7 +6,7 @@ export default function () {
// TODO(architect): Delete this test. It is now in devkit/build-angular.
// Fails on single run with broken compilation.
return writeFile('src/app.component.spec.ts', '<p> definitely not typescript </p>').then(() =>
return writeFile('src/app.spec.ts', '<p> definitely not typescript </p>').then(() =>
expectToFail(() => ng('test', '--watch=false')),
);
}

View File

@ -3,12 +3,12 @@ import { writeFile } from '../../utils/fs';
export default async function () {
await writeFile(
'src/app/app.component.spec.ts',
'src/app/app.spec.ts',
`
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { App } from './app';
describe('AppComponent', () => {
describe('App', () => {
beforeAll(() => {
jasmine.clock().install();
});
@ -18,11 +18,11 @@ export default async function () {
});
beforeEach(() => TestBed.configureTestingModule({
imports: [AppComponent]
imports: [App]
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const fixture = TestBed.createComponent(App);
expect(fixture.componentInstance).toBeTruthy();
});
});

View File

@ -16,31 +16,31 @@ export default async function () {
declare var stringScriptGlobal: any;
declare var inputScriptGlobal: any;
`,
'src/app/app.component.ts': `
'src/app/app.ts': `
import { Component } from '@angular/core';
@Component({ selector: 'app-root', template: '', standalone: false })
export class AppComponent {
export class App {
stringScriptGlobalProp = stringScriptGlobal;
inputScriptGlobalProp = inputScriptGlobal;
}
`,
'src/app/app.component.spec.ts': `
'src/app/app.spec.ts': `
import { TestBed } from '@angular/core/testing';
import { AppComponent } from './app.component';
import { App } from './app';
describe('AppComponent', () => {
describe('App', () => {
beforeEach(() => TestBed.configureTestingModule({
declarations: [AppComponent]
declarations: [App]
}));
it('should have access to string-script.js', () => {
let app = TestBed.createComponent(AppComponent).debugElement.componentInstance;
let app = TestBed.createComponent(App).debugElement.componentInstance;
expect(app.stringScriptGlobalProp).toEqual('string-scripts.js');
});
it('should have access to input-script.js', () => {
let app = TestBed.createComponent(AppComponent).debugElement.componentInstance;
let app = TestBed.createComponent(App).debugElement.componentInstance;
expect(app.inputScriptGlobalProp).toEqual('input-scripts.js');
});
});

View File

@ -6,7 +6,7 @@ import { assertIsError } from '../../utils/utils';
export default async function () {
await writeFile(
'src/app/app.component.spec.ts',
'src/app/app.spec.ts',
`
it('should fail', () => {
expect(undefined).toBeTruthy();
@ -20,7 +20,7 @@ export default async function () {
throw new Error('ng test should have failed.');
} catch (error) {
assertIsError(error);
assert.match(error.message, /\(src\/app\/app\.component\.spec\.ts:3:27/);
assert.match(error.message, /\(src\/app\/app\.spec\.ts:3:27/);
assert.doesNotMatch(error.message, /_karma_webpack_/);
}

View File

@ -19,14 +19,14 @@ export default async function () {
await installWorkspacePackages();
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
export const routes: Routes = [
{ path: 'home', component: HomeComponent }
{ path: 'home', component: Home }
];
`,
'src/app/app.routes.server.ts': `
@ -87,7 +87,7 @@ export default async function () {
// Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html',
'src/app/home/home.ng.html',
'home works',
'yay home works!!!',
true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('fastify@5');
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
export const routes: Routes = [
{ path: 'home', component: HomeComponent }
{ path: 'home', component: Home }
];
`,
'src/app/app.routes.server.ts': `
@ -87,7 +87,7 @@ export default async function () {
// Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html',
'src/app/home/home.ng.html',
'home works',
'yay home works!!!',
true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('h3@1');
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
export const routes: Routes = [
{ path: 'home', component: HomeComponent }
{ path: 'home', component: Home }
];
`,
'src/app/app.routes.server.ts': `
@ -78,7 +78,7 @@ export default async function () {
// Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html',
'src/app/home/home.ng.html',
'home works',
'yay home works!!!',
true,

View File

@ -20,14 +20,14 @@ export default async function () {
await installPackage('hono@4');
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
export const routes: Routes = [
{ path: 'home', component: HomeComponent }
{ path: 'home', component: Home }
];
`,
'src/app/app.routes.server.ts': `
@ -70,7 +70,7 @@ export default async function () {
// Modify the home component and validate the change.
await modifyFileAndWaitUntilUpdated(
'src/app/home/home.component.ng.html',
'src/app/home/home.ng.html',
'home works',
'yay home works!!!',
true,

View File

@ -22,7 +22,7 @@ export default async function () {
// Create Error.
await appendToFile(
'src/app/app.component.ts',
'src/app/app.ts',
`
(() => {
throw new Error('something happened!');
@ -37,7 +37,7 @@ export default async function () {
// The error is also sent in the browser, so we don't need to scrap the stderr.
match(
text,
/something happened.+at eval \(.+[\\/]+e2e-test[\\/]+test-project[\\/]+src[\\/]+app[\\/]+app\.component\.ts:\d+:\d+\)/,
/something happened.+at eval \(.+[\\/]+e2e-test[\\/]+test-project[\\/]+src[\\/]+app[\\/]+app\.ts:\d+:\d+\)/,
);
doesNotMatch(text, /vite-root/);
}

View File

@ -18,14 +18,14 @@ export default async function () {
await installWorkspacePackages();
await writeMultipleFiles({
// Replace the template of app.component.ng.html as it makes it harder to debug
'src/app/app.component.ng.html': '<router-outlet />',
// Replace the template of app.ng.html as it makes it harder to debug
'src/app/app.ng.html': '<router-outlet />',
'src/app/app.routes.ts': `
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { Home } from './home/home';
export const routes: Routes = [
{ path: 'home', component: HomeComponent }
{ path: 'home', component: Home }
];
`,
'src/app/app.routes.server.ts': `