Skip to content

Commit c91e18f

Browse files
committed
fix(@schematics/angular): generate modules with a dash type separator
To align with the updated style guide, Angular v20 will generate modules with file extension `module` type prefixed with a `-` separator instead of a `.` by default. Projects will automatically use this naming convention. Projects can however opt-out by setting the `typeSeparator` option to `.` for the module schematic. This can be done as a default in the `angular.json` or directly on the commandline via `--type-separator=.` when executing `ng generate`. As an example, `example.module.ts` will now be named `example-module.ts`. The TypeScript declaration will continue to contain `Module` such as with `ExampleModule`.
1 parent 3df7b6c commit c91e18f

File tree

13 files changed

+86
-79
lines changed

13 files changed

+86
-79
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { NgModule<% if(experimentalZoneless) { %>, provideExperimentalZonelessChangeDetection<% } %> } from '@angular/core';
22
import { BrowserModule } from '@angular/platform-browser';
33
<% if (routing) { %>
4-
import { AppRoutingModule } from './app-routing.module';<% } %>
4+
import { AppRoutingModule } from './app-routing-module';<% } %>
55
import { App } from './app';
66

77
@NgModule({

packages/schematics/angular/application/files/module-files/src/main.ts.template

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<% if(!!viewEncapsulation) { %>import { ViewEncapsulation } from '@angular/core';
22
<% }%>import { platformBrowser } from '@angular/platform-browser';
3-
import { AppModule } from './app/app.module';
3+
import { AppModule } from './app/app-module';
44

55
platformBrowser().bootstrapModule(AppModule, {
66
<% if(!experimentalZoneless) { %>ngZoneEventCoalescing: true,<% } %><% if(!!viewEncapsulation) { %>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { NgModule } from '@angular/core';<% if (commonModule) { %>
22
import { CommonModule } from '@angular/common';<% } %><% if (lazyRouteWithoutRouteModule) { %>
33
import { Routes, RouterModule } from '@angular/router';<% } %>
44
<% if ((!lazyRoute && routing) || lazyRouteWithRouteModule) { %>
5-
import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing.module';<% } %>
5+
import { <%= classify(name) %>RoutingModule } from './<%= dasherize(name) %>-routing<%= typeSeparator %>module';<% } %>
66
<% if (lazyRouteWithoutRouteModule) { %>
77
const routes: Routes = [
88
{ path: '', component: <%= classify(name) %> }

packages/schematics/angular/module/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function buildRelativeModulePath(options: ModuleOptions, modulePath: string): st
4040
const importModulePath = join(
4141
options.path ?? '',
4242
options.flat ? '' : strings.dasherize(options.name),
43-
strings.dasherize(options.name) + '.module',
43+
strings.dasherize(options.name) + options.typeSeparator + 'module',
4444
);
4545

4646
return buildRelativePath(modulePath, importModulePath);
@@ -153,7 +153,7 @@ export default function (options: ModuleOptions): Rule {
153153
const templateSource = apply(url('./files'), [
154154
options.routing || (isLazyLoadedModuleGen && routingModulePath)
155155
? noop()
156-
: filter((path) => !path.endsWith('-routing.module.ts.template')),
156+
: filter((path) => !path.includes('-routing')),
157157
applyTemplates({
158158
...strings,
159159
'if-flat': (s: string) => (options.flat ? '' : s),
@@ -167,7 +167,7 @@ export default function (options: ModuleOptions): Rule {
167167
const moduleDasherized = strings.dasherize(options.name);
168168
const modulePath = `${
169169
!options.flat ? moduleDasherized + '/' : ''
170-
}${moduleDasherized}.module.ts`;
170+
}${moduleDasherized}${options.typeSeparator}module.ts`;
171171

172172
const componentOptions: ComponentOptions = {
173173
module: modulePath,

packages/schematics/angular/module/index_spec.ts

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -49,33 +49,33 @@ describe('Module Schematic', () => {
4949

5050
const tree = await schematicRunner.runSchematic('module', options, appTree);
5151
const files = tree.files;
52-
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
52+
expect(files).toContain('/projects/bar/src/app/foo/foo-module.ts');
5353
});
5454

5555
it('should import into another module', async () => {
56-
const options = { ...defaultOptions, module: 'app.module.ts' };
56+
const options = { ...defaultOptions, module: 'app-module.ts' };
5757

5858
const tree = await schematicRunner.runSchematic('module', options, appTree);
59-
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
60-
expect(content).toMatch(/import { FooModule } from '.\/foo\/foo.module'/);
59+
const content = tree.readContent('/projects/bar/src/app/app-module.ts');
60+
expect(content).toMatch(/import { FooModule } from '.\/foo\/foo-module'/);
6161
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
6262
});
6363

6464
it('should import into another module when using flat', async () => {
65-
const options = { ...defaultOptions, flat: true, module: 'app.module.ts' };
65+
const options = { ...defaultOptions, flat: true, module: 'app-module.ts' };
6666

6767
const tree = await schematicRunner.runSchematic('module', options, appTree);
68-
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
69-
expect(content).toMatch(/import { FooModule } from '.\/foo.module'/);
68+
const content = tree.readContent('/projects/bar/src/app/app-module.ts');
69+
expect(content).toMatch(/import { FooModule } from '.\/foo-module'/);
7070
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
7171
});
7272

7373
it('should import into another module when using flat', async () => {
74-
const options = { ...defaultOptions, flat: true, module: 'app.module.ts' };
74+
const options = { ...defaultOptions, flat: true, module: 'app-module.ts' };
7575

7676
const tree = await schematicRunner.runSchematic('module', options, appTree);
77-
const content = tree.readContent('/projects/bar/src/app/app.module.ts');
78-
expect(content).toMatch(/import { FooModule } from '.\/foo.module'/);
77+
const content = tree.readContent('/projects/bar/src/app/app-module.ts');
78+
expect(content).toMatch(/import { FooModule } from '.\/foo-module'/);
7979
expect(content).toMatch(/imports: \[[^\]]*FooModule[^\]]*\]/m);
8080
});
8181

@@ -102,21 +102,21 @@ describe('Module Schematic', () => {
102102
tree,
103103
);
104104

105-
const content = tree.readContent('/projects/bar/src/app/sub1/test1/test1.module.ts');
106-
expect(content).toMatch(/import { Test2Module } from '..\/..\/sub2\/test2\/test2.module'/);
105+
const content = tree.readContent('/projects/bar/src/app/sub1/test1/test1-module.ts');
106+
expect(content).toMatch(/import { Test2Module } from '..\/..\/sub2\/test2\/test2-module'/);
107107
});
108108

109109
it('should create a routing module', async () => {
110110
const options = { ...defaultOptions, routing: true };
111111

112112
const tree = await schematicRunner.runSchematic('module', options, appTree);
113113
const files = tree.files;
114-
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
115-
expect(files).toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
116-
const moduleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
117-
expect(moduleContent).toMatch(/import { FooRoutingModule } from '.\/foo-routing.module'/);
114+
expect(files).toContain('/projects/bar/src/app/foo/foo-module.ts');
115+
expect(files).toContain('/projects/bar/src/app/foo/foo-routing-module.ts');
116+
const moduleContent = tree.readContent('/projects/bar/src/app/foo/foo-module.ts');
117+
expect(moduleContent).toMatch(/import { FooRoutingModule } from '.\/foo-routing-module'/);
118118
const routingModuleContent = tree.readContent(
119-
'/projects/bar/src/app/foo/foo-routing.module.ts',
119+
'/projects/bar/src/app/foo/foo-routing-module.ts',
120120
);
121121
expect(routingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
122122
});
@@ -126,15 +126,15 @@ describe('Module Schematic', () => {
126126

127127
const tree = await schematicRunner.runSchematic('module', options, appTree);
128128
const files = tree.files;
129-
expect(files).toContain('/projects/bar/src/app/two-word/two-word.module.ts');
129+
expect(files).toContain('/projects/bar/src/app/two-word/two-word-module.ts');
130130
});
131131

132132
it('should respect the sourceRoot value', async () => {
133133
const config = JSON.parse(appTree.readContent('/angular.json'));
134134
config.projects.bar.sourceRoot = 'projects/bar/custom';
135135
appTree.overwrite('/angular.json', JSON.stringify(config, null, 2));
136136
appTree = await schematicRunner.runSchematic('module', defaultOptions, appTree);
137-
expect(appTree.files).toContain('/projects/bar/custom/app/foo/foo.module.ts');
137+
expect(appTree.files).toContain('/projects/bar/custom/app/foo/foo-module.ts');
138138
});
139139

140140
describe('lazy route generator', () => {
@@ -150,23 +150,23 @@ describe('Module Schematic', () => {
150150

151151
expect(files).toEqual(
152152
jasmine.arrayContaining([
153-
'/projects/bar/src/app/foo/foo.module.ts',
154-
'/projects/bar/src/app/foo/foo-routing.module.ts',
153+
'/projects/bar/src/app/foo/foo-module.ts',
154+
'/projects/bar/src/app/foo/foo-routing-module.ts',
155155
'/projects/bar/src/app/foo/foo.ts',
156156
'/projects/bar/src/app/foo/foo.ng.html',
157157
'/projects/bar/src/app/foo/foo.css',
158158
]),
159159
);
160160

161161
const appRoutingModuleContent = tree.readContent(
162-
'/projects/bar/src/app/app-routing.module.ts',
162+
'/projects/bar/src/app/app-routing-module.ts',
163163
);
164164
expect(appRoutingModuleContent).toMatch(
165-
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo.module'\).then\(m => m.FooModule\)/,
165+
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo-module'\).then\(m => m.FooModule\)/,
166166
);
167167

168168
const fooRoutingModuleContent = tree.readContent(
169-
'/projects/bar/src/app/foo/foo-routing.module.ts',
169+
'/projects/bar/src/app/foo/foo-routing-module.ts',
170170
);
171171
expect(fooRoutingModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
172172
expect(fooRoutingModuleContent).toMatch(
@@ -176,7 +176,7 @@ describe('Module Schematic', () => {
176176

177177
it('should generate a lazy loaded module with embedded route declarations', async () => {
178178
appTree.overwrite(
179-
'/projects/bar/src/app/app.module.ts',
179+
'/projects/bar/src/app/app-module.ts',
180180
`
181181
import { NgModule } from '@angular/core';
182182
import { AppComponent } from './app';
@@ -195,23 +195,23 @@ describe('Module Schematic', () => {
195195
export class AppModule { }
196196
`,
197197
);
198-
appTree.delete('/projects/bar/src/app/app-routing.module.ts');
198+
appTree.delete('/projects/bar/src/app/app-routing-module.ts');
199199

200200
const tree = await schematicRunner.runSchematic('module', options, appTree);
201201
const files = tree.files;
202202

203-
expect(files).toContain('/projects/bar/src/app/foo/foo.module.ts');
204-
expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing.module.ts');
203+
expect(files).toContain('/projects/bar/src/app/foo/foo-module.ts');
204+
expect(files).not.toContain('/projects/bar/src/app/foo/foo-routing-module.ts');
205205
expect(files).toContain('/projects/bar/src/app/foo/foo.ts');
206206
expect(files).toContain('/projects/bar/src/app/foo/foo.ng.html');
207207
expect(files).toContain('/projects/bar/src/app/foo/foo.css');
208208

209-
const appModuleContent = tree.readContent('/projects/bar/src/app/app.module.ts');
209+
const appModuleContent = tree.readContent('/projects/bar/src/app/app-module.ts');
210210
expect(appModuleContent).toMatch(
211-
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo.module'\).then\(m => m.FooModule\)/,
211+
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo\/foo-module'\).then\(m => m.FooModule\)/,
212212
);
213213

214-
const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo.module.ts');
214+
const fooModuleContent = tree.readContent('/projects/bar/src/app/foo/foo-module.ts');
215215
expect(fooModuleContent).toMatch(/RouterModule.forChild\(routes\)/);
216216
expect(fooModuleContent).toMatch(
217217
/const routes: Routes = \[\r?\n?\s*{ path: '', component: Foo }\r?\n?\s*\];/,
@@ -228,19 +228,19 @@ describe('Module Schematic', () => {
228228

229229
expect(files).toEqual(
230230
jasmine.arrayContaining([
231-
'/projects/bar/src/app/foo.module.ts',
232-
'/projects/bar/src/app/foo-routing.module.ts',
231+
'/projects/bar/src/app/foo-module.ts',
232+
'/projects/bar/src/app/foo-routing-module.ts',
233233
'/projects/bar/src/app/foo.ts',
234234
'/projects/bar/src/app/foo.ng.html',
235235
'/projects/bar/src/app/foo.css',
236236
]),
237237
);
238238

239239
const appRoutingModuleContent = tree.readContent(
240-
'/projects/bar/src/app/app-routing.module.ts',
240+
'/projects/bar/src/app/app-routing-module.ts',
241241
);
242242
expect(appRoutingModuleContent).toMatch(
243-
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo.module'\).then\(m => m.FooModule\)/,
243+
/path: '\/new-route', loadChildren: \(\) => import\('.\/foo-module'\).then\(m => m.FooModule\)/,
244244
);
245245
});
246246

@@ -267,34 +267,34 @@ describe('Module Schematic', () => {
267267
);
268268
expect(tree.files).toEqual(
269269
jasmine.arrayContaining([
270-
'/projects/bar/src/app/foo/foo-routing.module.ts',
271-
'/projects/bar/src/app/foo/foo.module.ts',
272-
'/projects/bar/src/app/bar/bar-routing.module.ts',
273-
'/projects/bar/src/app/bar/bar.module.ts',
270+
'/projects/bar/src/app/foo/foo-routing-module.ts',
271+
'/projects/bar/src/app/foo/foo-module.ts',
272+
'/projects/bar/src/app/bar/bar-routing-module.ts',
273+
'/projects/bar/src/app/bar/bar-module.ts',
274274
'/projects/bar/src/app/bar/bar.ts',
275275
]),
276276
);
277277

278278
const barRoutingModuleContent = tree.readContent(
279-
'/projects/bar/src/app/bar/bar-routing.module.ts',
279+
'/projects/bar/src/app/bar/bar-routing-module.ts',
280280
);
281281
expect(barRoutingModuleContent).toContain(`path: '', component: Bar `);
282282

283283
const fooRoutingModuleContent = tree.readContent(
284-
'/projects/bar/src/app/foo/foo-routing.module.ts',
284+
'/projects/bar/src/app/foo/foo-routing-module.ts',
285285
);
286286
expect(fooRoutingModuleContent).toContain(
287-
`loadChildren: () => import('../bar/bar.module').then(m => m.BarModule)`,
287+
`loadChildren: () => import('../bar/bar-module').then(m => m.BarModule)`,
288288
);
289289
});
290290

291291
it('should not add reference to RouterModule when referencing lazy routing module', async () => {
292292
// Delete routing module
293-
appTree.delete('/projects/bar/src/app/app-routing.module.ts');
293+
appTree.delete('/projects/bar/src/app/app-routing-module.ts');
294294

295-
// Update app.module to contain the route config.
295+
// Update app-module to contain the route config.
296296
appTree.overwrite(
297-
'projects/bar/src/app/app.module.ts',
297+
'projects/bar/src/app/app-module.ts',
298298
`
299299
import { NgModule } from '@angular/core';
300300
import { RouterModule } from '@angular/router';
@@ -317,11 +317,11 @@ describe('Module Schematic', () => {
317317
name: 'bar',
318318
route: 'bar',
319319
routing: true,
320-
module: 'app.module.ts',
320+
module: 'app-module.ts',
321321
},
322322
appTree,
323323
);
324-
const content = tree.readContent('/projects/bar/src/app/bar/bar.module.ts');
324+
const content = tree.readContent('/projects/bar/src/app/bar/bar-module.ts');
325325
expect(content).toContain('RouterModule.forChild(routes)');
326326
expect(content).not.toContain('BarRoutingModule');
327327
});

packages/schematics/angular/module/schema.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
"type": "string",
6363
"description": "The declaring NgModule.",
6464
"alias": "m"
65+
},
66+
"typeSeparator": {
67+
"type": "string",
68+
"default": "-",
69+
"enum": ["-", "."]
6570
}
6671
},
6772
"required": ["name", "project"]

packages/schematics/angular/pipe/schema.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
"typeSeparator": {
6666
"type": "string",
6767
"default": "-",
68-
"enum": ["-", "."]
68+
"enum": ["-", "."],
69+
"description": "The separator character to use before the type within the generated file's name. For example, if you set the option to `.`, the file will be named `example.pipe.ts`."
6970
}
7071
},
7172
"required": ["name", "project"]

packages/schematics/angular/resolver/schema.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"typeSeparator": {
5050
"type": "string",
5151
"default": "-",
52-
"enum": ["-", "."]
52+
"enum": ["-", "."],
53+
"description": "The separator character to use before the type within the generated file's name. For example, if you set the option to `.`, the file will be named `example.resolver.ts`."
5354
}
5455
},
5556
"required": ["name", "project"]

tests/legacy-cli/e2e/tests/build/prerender/discover-routes-ngmodule.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default async function () {
4646

4747
// Add routes
4848
await writeFile(
49-
`projects/${projectName}/src/app/app-routing.module.ts`,
49+
`projects/${projectName}/src/app/app-routing-module.ts`,
5050
`
5151
import { NgModule } from '@angular/core';
5252
import { RouterModule, Routes } from '@angular/router';
@@ -91,9 +91,9 @@ export default async function () {
9191

9292
// Generate lazy routes
9393
const lazyModules: [route: string, moduleName: string][] = [
94-
['lazy-one', 'app.module'],
95-
['lazy-one-child', 'lazy-one/lazy-one.module'],
96-
['lazy-two', 'app.module'],
94+
['lazy-one', 'app-module'],
95+
['lazy-one-child', 'lazy-one/lazy-one-module'],
96+
['lazy-two', 'app-module'],
9797
];
9898

9999
for (const [route, moduleName] of lazyModules) {

0 commit comments

Comments
 (0)