Skip to content

Commit 053c875

Browse files
committed
feat(angular): generate pipes with a - type separator
1 parent 1070e18 commit 053c875

File tree

15 files changed

+282
-51
lines changed

15 files changed

+282
-51
lines changed

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,15 @@
1515
"command": "nx g @nx/angular:pipe mylib/src/lib/foo.pipe.ts"
1616
},
1717
{
18-
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
18+
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo-pipe.ts`",
1919
"command": "nx g @nx/angular:pipe mylib/src/lib/foo"
2020
},
2121
{
22-
"description": "Generate a pipe with the exported symbol different from the file name. It results in the pipe `CustomPipe` at `mylib/src/lib/foo.pipe.ts`",
22+
"description": "Generate a pipe with a different type separator. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
23+
"command": "nx g @nx/angular:pipe mylib/src/lib/foo --typeSeparator=."
24+
},
25+
{
26+
"description": "Generate a pipe with the exported symbol different from the file name. It results in the pipe `CustomPipe` at `mylib/src/lib/foo-pipe.ts`",
2327
"command": "nx g @nx/angular:pipe mylib/src/lib/foo --name=custom"
2428
}
2529
],
@@ -59,6 +63,11 @@
5963
"default": false,
6064
"description": "The declaring NgModule exports this pipe."
6165
},
66+
"typeSeparator": {
67+
"type": "string",
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`. It defaults to '-' for Angular v20+. For versions below v20, it defaults to '.'."
70+
},
6271
"skipFormat": {
6372
"type": "boolean",
6473
"default": false,

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@
5151
"default": true,
5252
"x-priority": "important"
5353
},
54+
"typeSeparator": {
55+
"type": "string",
56+
"enum": ["-", "."],
57+
"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`. It defaults to '-' for Angular v20+. For versions below v20, it defaults to '.'."
58+
},
5459
"skipFormat": {
5560
"description": "Skip formatting files.",
5661
"type": "boolean",

packages/angular/src/generators/pipe/__snapshots__/pipe.spec.ts.snap

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
exports[`pipe generator --no-standalone should export the pipe correctly when directory is nested deeper 1`] = `
44
"import { NgModule } from '@angular/core';
5-
import { TestPipe } from './my-pipes/test/test.pipe';
5+
import { TestPipe } from './my-pipes/test/test-pipe';
66
@NgModule({
77
imports: [],
88
declarations: [TestPipe],
@@ -28,7 +28,7 @@ export class TestPipe implements PipeTransform {
2828
`;
2929

3030
exports[`pipe generator --no-standalone should generate a pipe with test files and attach to the NgModule automatically 2`] = `
31-
"import { TestPipe } from './test.pipe';
31+
"import { TestPipe } from './test-pipe';
3232
3333
describe('TestPipe', () => {
3434
it('create an instance', () => {
@@ -41,7 +41,7 @@ describe('TestPipe', () => {
4141

4242
exports[`pipe generator --no-standalone should generate a pipe with test files and attach to the NgModule automatically 3`] = `
4343
"import { NgModule } from '@angular/core';
44-
import { TestPipe } from './test.pipe';
44+
import { TestPipe } from './test-pipe';
4545
@NgModule({
4646
imports: [],
4747
declarations: [TestPipe],
@@ -67,7 +67,7 @@ export class TestPipe implements PipeTransform {
6767
`;
6868

6969
exports[`pipe generator --no-standalone should import the pipe correctly when files are flat 2`] = `
70-
"import { TestPipe } from './test.pipe';
70+
"import { TestPipe } from './test-pipe';
7171
7272
describe('TestPipe', () => {
7373
it('create an instance', () => {
@@ -80,7 +80,7 @@ describe('TestPipe', () => {
8080

8181
exports[`pipe generator --no-standalone should import the pipe correctly when files are flat 3`] = `
8282
"import { NgModule } from '@angular/core';
83-
import { TestPipe } from './test/test.pipe';
83+
import { TestPipe } from './test/test-pipe';
8484
@NgModule({
8585
imports: [],
8686
declarations: [TestPipe],
@@ -106,7 +106,7 @@ export class TestPipe implements PipeTransform {
106106
`;
107107

108108
exports[`pipe generator --no-standalone should import the pipe correctly when files are flat but deeply nested 2`] = `
109-
"import { TestPipe } from './test.pipe';
109+
"import { TestPipe } from './test-pipe';
110110
111111
describe('TestPipe', () => {
112112
it('create an instance', () => {
@@ -119,7 +119,7 @@ describe('TestPipe', () => {
119119

120120
exports[`pipe generator --no-standalone should import the pipe correctly when files are flat but deeply nested 3`] = `
121121
"import { NgModule } from '@angular/core';
122-
import { TestPipe } from './my-pipes/test/test.pipe';
122+
import { TestPipe } from './my-pipes/test/test-pipe';
123123
@NgModule({
124124
imports: [],
125125
declarations: [TestPipe],
@@ -144,7 +144,7 @@ export class TestPipe implements PipeTransform {
144144
`;
145145

146146
exports[`pipe generator should generate correctly 2`] = `
147-
"import { TestPipe } from './test.pipe';
147+
"import { TestPipe } from './test-pipe';
148148
149149
describe('TestPipe', () => {
150150
it('create an instance', () => {

packages/angular/src/generators/pipe/lib/normalize-options.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ import type { Tree } from '@nx/devkit';
22
import { names } from '@nx/devkit';
33
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
44
import { validateClassName } from '../../utils/validations';
5+
import { getInstalledAngularVersionInfo } from '../../utils/version-utils';
56
import type { NormalizedSchema, Schema } from '../schema';
67

78
export async function normalizeOptions(
89
tree: Tree,
910
options: Schema
1011
): Promise<NormalizedSchema> {
12+
const { major: angularMajorVersion } = getInstalledAngularVersionInfo(tree);
13+
options.typeSeparator ??= angularMajorVersion < 20 ? '.' : '-';
14+
1115
const {
1216
artifactName: name,
1317
directory,
@@ -18,6 +22,7 @@ export async function normalizeOptions(
1822
name: options.name,
1923
path: options.path,
2024
suffix: 'pipe',
25+
suffixSeparator: options.typeSeparator,
2126
allowedFileExtensions: ['ts'],
2227
fileExtension: 'ts',
2328
});

packages/angular/src/generators/pipe/pipe.spec.ts

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { addProjectConfiguration, Tree } from '@nx/devkit';
1+
import { addProjectConfiguration, type Tree, updateJson } from '@nx/devkit';
22
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
33
import { pipeGenerator } from './pipe';
44
import type { Schema } from './schema';
@@ -21,12 +21,46 @@ describe('pipe generator', () => {
2121
await generatePipeWithDefaultOptions(tree, { skipFormat: false });
2222

2323
// ASSERT
24-
expect(tree.read('test/src/app/test.pipe.ts', 'utf-8')).toMatchSnapshot();
24+
expect(tree.read('test/src/app/test-pipe.ts', 'utf-8')).toMatchSnapshot();
2525
expect(
26-
tree.read('test/src/app/test.pipe.spec.ts', 'utf-8')
26+
tree.read('test/src/app/test-pipe.spec.ts', 'utf-8')
2727
).toMatchSnapshot();
2828
});
2929

30+
it('should generate files with the provided type separator', async () => {
31+
await generatePipeWithDefaultOptions(tree, {
32+
typeSeparator: '.',
33+
skipFormat: false,
34+
});
35+
36+
expect(tree.read('test/src/app/test.pipe.ts', 'utf-8'))
37+
.toMatchInlineSnapshot(`
38+
"import { Pipe, PipeTransform } from '@angular/core';
39+
40+
@Pipe({
41+
name: 'test',
42+
})
43+
export class TestPipe implements PipeTransform {
44+
transform(value: unknown, ...args: unknown[]): unknown {
45+
return null;
46+
}
47+
}
48+
"
49+
`);
50+
expect(tree.read('test/src/app/test.pipe.spec.ts', 'utf-8'))
51+
.toMatchInlineSnapshot(`
52+
"import { TestPipe } from './test.pipe';
53+
54+
describe('TestPipe', () => {
55+
it('create an instance', () => {
56+
const pipe = new TestPipe();
57+
expect(pipe).toBeTruthy();
58+
});
59+
});
60+
"
61+
`);
62+
});
63+
3064
it('should handle path with file extension', async () => {
3165
await generatePipeWithDefaultOptions(tree, {
3266
path: 'test/src/app/test.pipe.ts',
@@ -61,7 +95,7 @@ describe('pipe generator', () => {
6195

6296
// ASSERT
6397
expect(
64-
tree.exists('test/src/app/my-pipes/test/test.pipe.spec.ts')
98+
tree.exists('test/src/app/my-pipes/test/test-pipe.spec.ts')
6599
).toBeFalsy();
66100
});
67101

@@ -86,9 +120,9 @@ describe('pipe generator', () => {
86120
});
87121

88122
// ASSERT
89-
expect(tree.read('test/src/app/test.pipe.ts', 'utf-8')).toMatchSnapshot();
123+
expect(tree.read('test/src/app/test-pipe.ts', 'utf-8')).toMatchSnapshot();
90124
expect(
91-
tree.read('test/src/app/test.pipe.spec.ts', 'utf-8')
125+
tree.read('test/src/app/test-pipe.spec.ts', 'utf-8')
92126
).toMatchSnapshot();
93127
expect(
94128
tree.read('test/src/app/test.module.ts', 'utf-8')
@@ -106,10 +140,10 @@ describe('pipe generator', () => {
106140

107141
// ASSERT
108142
expect(
109-
tree.read('test/src/app/test/test.pipe.ts', 'utf-8')
143+
tree.read('test/src/app/test/test-pipe.ts', 'utf-8')
110144
).toMatchSnapshot();
111145
expect(
112-
tree.read('test/src/app/test/test.pipe.spec.ts', 'utf-8')
146+
tree.read('test/src/app/test/test-pipe.spec.ts', 'utf-8')
113147
).toMatchSnapshot();
114148
expect(
115149
tree.read('test/src/app/test.module.ts', 'utf-8')
@@ -127,10 +161,10 @@ describe('pipe generator', () => {
127161

128162
// ASSERT
129163
expect(
130-
tree.read('test/src/app/my-pipes/test/test.pipe.ts', 'utf-8')
164+
tree.read('test/src/app/my-pipes/test/test-pipe.ts', 'utf-8')
131165
).toMatchSnapshot();
132166
expect(
133-
tree.read('test/src/app/my-pipes/test/test.pipe.spec.ts', 'utf-8')
167+
tree.read('test/src/app/my-pipes/test/test-pipe.spec.ts', 'utf-8')
134168
).toMatchSnapshot();
135169
expect(
136170
tree.read('test/src/app/test.module.ts', 'utf-8')
@@ -169,6 +203,47 @@ describe('pipe generator', () => {
169203
);
170204
});
171205
});
206+
207+
describe('compat', () => {
208+
it('should generate the files with the "." type separator for versions below v20', async () => {
209+
updateJson(tree, 'package.json', (json) => {
210+
json.dependencies = {
211+
...json.dependencies,
212+
'@angular/core': '~19.2.0',
213+
};
214+
return json;
215+
});
216+
217+
await generatePipeWithDefaultOptions(tree, { skipFormat: false });
218+
219+
expect(tree.read('test/src/app/test.pipe.ts', 'utf-8'))
220+
.toMatchInlineSnapshot(`
221+
"import { Pipe, PipeTransform } from '@angular/core';
222+
223+
@Pipe({
224+
name: 'test',
225+
})
226+
export class TestPipe implements PipeTransform {
227+
transform(value: unknown, ...args: unknown[]): unknown {
228+
return null;
229+
}
230+
}
231+
"
232+
`);
233+
expect(tree.read('test/src/app/test.pipe.spec.ts', 'utf-8'))
234+
.toMatchInlineSnapshot(`
235+
"import { TestPipe } from './test.pipe';
236+
237+
describe('TestPipe', () => {
238+
it('create an instance', () => {
239+
const pipe = new TestPipe();
240+
expect(pipe).toBeTruthy();
241+
});
242+
});
243+
"
244+
`);
245+
});
246+
});
172247
});
173248

174249
function addModule(tree: Tree) {

packages/angular/src/generators/pipe/schema.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface Schema {
66
standalone?: boolean;
77
module?: string;
88
export?: boolean;
9+
typeSeparator?: string;
910
skipFormat?: boolean;
1011
}
1112

packages/angular/src/generators/pipe/schema.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@
1212
"command": "nx g @nx/angular:pipe mylib/src/lib/foo.pipe.ts"
1313
},
1414
{
15-
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
15+
"description": "Generate a pipe without providing the file extension. It results in the pipe `FooPipe` at `mylib/src/lib/foo-pipe.ts`",
1616
"command": "nx g @nx/angular:pipe mylib/src/lib/foo"
1717
},
1818
{
19-
"description": "Generate a pipe with the exported symbol different from the file name. It results in the pipe `CustomPipe` at `mylib/src/lib/foo.pipe.ts`",
19+
"description": "Generate a pipe with a different type separator. It results in the pipe `FooPipe` at `mylib/src/lib/foo.pipe.ts`",
20+
"command": "nx g @nx/angular:pipe mylib/src/lib/foo --typeSeparator=."
21+
},
22+
{
23+
"description": "Generate a pipe with the exported symbol different from the file name. It results in the pipe `CustomPipe` at `mylib/src/lib/foo-pipe.ts`",
2024
"command": "nx g @nx/angular:pipe mylib/src/lib/foo --name=custom"
2125
}
2226
],
@@ -59,6 +63,11 @@
5963
"default": false,
6064
"description": "The declaring NgModule exports this pipe."
6165
},
66+
"typeSeparator": {
67+
"type": "string",
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`. It defaults to '-' for Angular v20+. For versions below v20, it defaults to '.'."
70+
},
6271
"skipFormat": {
6372
"type": "boolean",
6473
"default": false,

packages/angular/src/generators/scam-pipe/lib/convert-pipe-to-scam.spec.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { convertPipeToScam } from './convert-pipe-to-scam';
66
describe('convertPipeToScam', () => {
77
it('should create the scam pipe inline correctly', async () => {
88
// ARRANGE
9-
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
9+
const tree = createTreeWithEmptyWorkspace();
1010
addProjectConfiguration(tree, 'app1', {
1111
projectType: 'application',
1212
sourceRoot: 'apps/app1/src',
@@ -26,8 +26,8 @@ describe('convertPipeToScam', () => {
2626
convertPipeToScam(tree, {
2727
path: 'apps/app1/src/app/example/example',
2828
directory: 'apps/app1/src/app/example',
29-
fileName: 'example.pipe',
30-
filePath: 'apps/app1/src/app/example/example.pipe.ts',
29+
fileName: 'example-pipe',
30+
filePath: 'apps/app1/src/app/example/example-pipe.ts',
3131
name: 'example',
3232
projectName: 'app1',
3333
export: false,
@@ -37,7 +37,7 @@ describe('convertPipeToScam', () => {
3737

3838
// ASSERT
3939
const pipeSource = tree.read(
40-
'apps/app1/src/app/example/example.pipe.ts',
40+
'apps/app1/src/app/example/example-pipe.ts',
4141
'utf-8'
4242
);
4343
expect(pipeSource).toMatchInlineSnapshot(`
@@ -66,7 +66,7 @@ describe('convertPipeToScam', () => {
6666

6767
it('should create the scam pipe separately correctly', async () => {
6868
// ARRANGE
69-
const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
69+
const tree = createTreeWithEmptyWorkspace();
7070
addProjectConfiguration(tree, 'app1', {
7171
projectType: 'application',
7272
sourceRoot: 'apps/app1/src',
@@ -85,8 +85,8 @@ describe('convertPipeToScam', () => {
8585
convertPipeToScam(tree, {
8686
path: 'apps/app1/src/app/example/example',
8787
directory: 'apps/app1/src/app/example',
88-
fileName: 'example.pipe',
89-
filePath: 'apps/app1/src/app/example/example.pipe.ts',
88+
fileName: 'example-pipe',
89+
filePath: 'apps/app1/src/app/example/example-pipe.ts',
9090
name: 'example',
9191
projectName: 'app1',
9292
export: false,
@@ -102,7 +102,7 @@ describe('convertPipeToScam', () => {
102102
expect(pipeModuleSource).toMatchInlineSnapshot(`
103103
"import { NgModule } from '@angular/core';
104104
import { CommonModule } from '@angular/common';
105-
import { ExamplePipe } from './example.pipe';
105+
import { ExamplePipe } from './example-pipe';
106106
107107
@NgModule({
108108
imports: [CommonModule],

0 commit comments

Comments
 (0)