Skip to content

Commit 2fd9912

Browse files
committed
feat(@schematics/angular): support different file name style guides in ng new
Introduces the ability to configure the file naming convention for generated files directly within the `ng new` schematic. This allows users to create new workspaces that adhere to the 2016 style guide conventions, as an alternative to the default 2025 style guide. For more information, see the Angular Style Guide (https://angular.dev/style-guide). When a user runs `ng new --file-name-style-guide 2016`: - The `ng-new` schematic passes the style guide option down to the `workspace` and `application` sub-schematics. - The `workspace` schematic configures the `schematics` section of the new `angular.json` to use the 2016 naming conventions for future `ng generate` commands. - The `application` schematic generates the initial application files with the appropriate suffixes (e.g., `app.component.ts`). This addresses community feedback requesting a way to maintain the previous file naming structure for consistency in existing projects and workflows. Fixes #30594
1 parent 261dbb3 commit 2fd9912

12 files changed

Lines changed: 80 additions & 1 deletion

File tree

packages/schematics/angular/application/files/common-files/src/app/app.html.template renamed to packages/schematics/angular/application/files/common-files/src/app/app__suffix__.html.template

File renamed without changes.

packages/schematics/angular/application/files/module-files/src/app/app.spec.ts.template renamed to packages/schematics/angular/application/files/module-files/src/app/app__suffix__.spec.ts.template

File renamed without changes.

packages/schematics/angular/application/files/module-files/src/app/app.ts.template renamed to packages/schematics/angular/application/files/module-files/src/app/app__suffix__.ts.template

File renamed without changes.

packages/schematics/angular/application/files/standalone-files/src/app/app.spec.ts.template renamed to packages/schematics/angular/application/files/standalone-files/src/app/app__suffix__.spec.ts.template

File renamed without changes.

packages/schematics/angular/application/files/standalone-files/src/app/app.ts.template renamed to packages/schematics/angular/application/files/standalone-files/src/app/app__suffix__.ts.template

File renamed without changes.

packages/schematics/angular/application/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ export default function (options: ApplicationOptions): Rule {
6767
const { appDir, appRootSelector, componentOptions, folderName, sourceDir } =
6868
await getAppOptions(host, options);
6969

70+
const suffix = options.fileNameStyleGuide === '2016' ? '.component' : '';
71+
7072
return chain([
7173
addAppToWorkspaceFile(options, appDir),
7274
addTsProjectReference('./' + join(normalize(appDir), 'tsconfig.app.json')),
@@ -108,6 +110,7 @@ export default function (options: ApplicationOptions): Rule {
108110
relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir),
109111
appName: options.name,
110112
folderName,
113+
suffix,
111114
}),
112115
move(appDir),
113116
]),
@@ -119,7 +122,7 @@ export default function (options: ApplicationOptions): Rule {
119122
? filter((path) => !path.endsWith('tsconfig.spec.json.template'))
120123
: noop(),
121124
componentOptions.inlineTemplate
122-
? filter((path) => !path.endsWith('app.html.template'))
125+
? filter((path) => !path.endsWith('app__suffix__.html.template'))
123126
: noop(),
124127
applyTemplates({
125128
utils: strings,
@@ -128,6 +131,7 @@ export default function (options: ApplicationOptions): Rule {
128131
relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(appDir),
129132
appName: options.name,
130133
folderName,
134+
suffix,
131135
}),
132136
move(appDir),
133137
]),
@@ -389,5 +393,9 @@ function getComponentOptions(options: ApplicationOptions): Partial<ComponentOpti
389393
viewEncapsulation: options.viewEncapsulation,
390394
};
391395

396+
if (options.fileNameStyleGuide === '2016') {
397+
componentOptions.type = 'component';
398+
}
399+
392400
return componentOptions;
393401
}

packages/schematics/angular/application/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@
127127
"x-prompt": "Do you want to create a 'zoneless' application without zone.js?",
128128
"type": "boolean",
129129
"default": false
130+
},
131+
"fileNameStyleGuide": {
132+
"type": "string",
133+
"enum": ["2016", "2025"],
134+
"default": "2025",
135+
"description": "The file naming convention to use for generated files. The '2025' style guide (default) uses a concise format (e.g., `app.ts` for the root component), while the '2016' style guide includes the type in the file name (e.g., `app.component.ts`). For more information, see the Angular Style Guide (https://angular.dev/style-guide)."
130136
}
131137
},
132138
"required": ["name"]

packages/schematics/angular/ng-new/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export default function (options: NgNewOptions): Rule {
3939
minimal: options.minimal,
4040
strict: options.strict,
4141
packageManager: options.packageManager,
42+
fileNameStyleGuide: options.fileNameStyleGuide,
4243
};
4344
const applicationOptions: ApplicationOptions = {
4445
projectRoot: '',
@@ -58,6 +59,7 @@ export default function (options: NgNewOptions): Rule {
5859
standalone: options.standalone,
5960
ssr: options.ssr,
6061
zoneless: options.zoneless,
62+
fileNameStyleGuide: options.fileNameStyleGuide,
6163
};
6264

6365
return chain([

packages/schematics/angular/ng-new/index_spec.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,4 +128,29 @@ describe('Ng New Schematic', () => {
128128
const stylesContent = tree.readContent('/bar/src/styles.css');
129129
expect(stylesContent).toContain('@import "tailwindcss";');
130130
});
131+
132+
it(`should create files with file name style guide '2016'`, async () => {
133+
const options = { ...defaultOptions, fileNameStyleGuide: '2016' };
134+
135+
const tree = await schematicRunner.runSchematic('ng-new', options);
136+
const files = tree.files;
137+
expect(files).toEqual(
138+
jasmine.arrayContaining([
139+
'/bar/src/app/app.component.css',
140+
'/bar/src/app/app.component.html',
141+
'/bar/src/app/app.component.spec.ts',
142+
'/bar/src/app/app.component.ts',
143+
]),
144+
);
145+
146+
const { schematics } = JSON.parse(tree.readContent('/bar/angular.json'));
147+
expect(schematics['@schematics/angular:component'].type).toBe('component');
148+
expect(schematics['@schematics/angular:directive'].type).toBe('directive');
149+
expect(schematics['@schematics/angular:service'].type).toBe('service');
150+
expect(schematics['@schematics/angular:guard'].typeSeparator).toBe('.');
151+
expect(schematics['@schematics/angular:interceptor'].typeSeparator).toBe('.');
152+
expect(schematics['@schematics/angular:module'].typeSeparator).toBe('.');
153+
expect(schematics['@schematics/angular:pipe'].typeSeparator).toBe('.');
154+
expect(schematics['@schematics/angular:resolver'].typeSeparator).toBe('.');
155+
});
131156
});

packages/schematics/angular/ng-new/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@
151151
"type": "string",
152152
"enum": ["none", "gemini", "copilot", "claude", "cursor", "jetbrains", "windsurf"]
153153
}
154+
},
155+
"fileNameStyleGuide": {
156+
"type": "string",
157+
"enum": ["2016", "2025"],
158+
"default": "2025",
159+
"description": "The file naming convention to use for generated files. The '2025' style guide (default) uses a concise format (e.g., `app.ts` for the root component), while the '2016' style guide includes the type in the file name (e.g., `app.component.ts`). For more information, see the Angular Style Guide (https://angular.dev/style-guide)."
154160
}
155161
},
156162
"required": ["name", "version"]

0 commit comments

Comments
 (0)