Skip to content

Commit a4534f4

Browse files
authored
Merge pull request #113 from Service-Soft/update-to-angular-20
updated to angular 20
2 parents 9f59c01 + 91bdc78 commit a4534f4

19 files changed

Lines changed: 317 additions & 70 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
- uses: actions/checkout@v4
1919
- run: docker pull adminer
2020
- run: docker pull postgres
21-
- run: npm i -g @angular/cli@18 @loopback/cli@6 @nestjs/cli@11
21+
- run: npm i -g @angular/cli@20 zibri-cli @loopback/cli@6 @nestjs/cli@11
2222
- run: npm ci
2323
- run: npm run build
2424
- run: npm run test

src/__testing__/mock/constants.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
/* eslint-disable jsdoc/require-jsdoc */
2-
import { ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES_FILE_NAME, APP_CONFIG_FILE_NAME, APPS_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME, LOCAL_DOCKER_COMPOSE_FILE_NAME, WORKSPACE_FILE_NAME, BASE_TS_CONFIG_FILE_NAME, STAGE_DOCKER_COMPOSE_FILE_NAME, ENV_PUBLIC_FILE_NAME } from '../../constants';
2+
import { ANGULAR_JSON_FILE_NAME, ANGULAR_ROUTES_FILE_NAME, APP_CONFIG_FILE_NAME, APPS_DIRECTORY_NAME, DEV_DOCKER_COMPOSE_FILE_NAME, PROD_DOCKER_COMPOSE_FILE_NAME, ENV_FILE_NAME, ENVIRONMENT_MODEL_TS_FILE_NAME, ENVIRONMENT_TS_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GLOBAL_ENVIRONMENT_MODEL_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME, LOCAL_DOCKER_COMPOSE_FILE_NAME, WORKSPACE_FILE_NAME, BASE_TS_CONFIG_FILE_NAME, STAGE_DOCKER_COMPOSE_FILE_NAME, ENV_PUBLIC_FILE_NAME, ANGULAR_APP_COMPONENT_FILE_NAME } from '../../constants';
33
import { OmitStrict } from '../../types';
44
import { getPath, Path } from '../../utilities';
55

6-
export const MAX_ADD_TIME: number = 90000;
6+
export const MAX_ADD_TIME: number = 100000;
77

88
export const MAX_GEN_CODE_TIME: number = 10000;
99

@@ -86,8 +86,8 @@ export function getMockConstants(projectName: string): MockConstants {
8686
ANGULAR_ESLINT_CONFIG_MJS: getPath(ANGULAR_APP_DIR, ESLINT_CONFIG_FILE_NAME),
8787
ANGULAR_APP_NAME: ANGULAR_APP_NAME,
8888
ANGULAR_APP_DIR: ANGULAR_APP_DIR,
89-
ANGULAR_APP_COMPONENT_TS: getPath(ANGULAR_APP_DIR, 'src', 'app', 'app.component.ts'),
90-
ANGULAR_APP_COMPONENT_HTML: getPath(ANGULAR_APP_DIR, 'src', 'app', 'app.component.html'),
89+
ANGULAR_APP_COMPONENT_TS: getPath(ANGULAR_APP_DIR, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME),
90+
ANGULAR_APP_COMPONENT_HTML: getPath(ANGULAR_APP_DIR, 'src', 'app', 'app.html'),
9191
ANGULAR_APP_ROUTES_TS: getPath(ANGULAR_APP_DIR, 'src', 'app', 'app.routes.ts'),
9292
ANGULAR_ROUTES_TS: getPath(ANGULAR_APP_DIR, 'src', 'app', ANGULAR_ROUTES_FILE_NAME),
9393
ANGULAR_APP_CONFIG_TS: getPath(ANGULAR_APP_DIR, 'src', 'app', APP_CONFIG_FILE_NAME),

src/__testing__/mock/file-mock.utilities.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,17 @@ export abstract class FileMockUtilities {
114114
projectType: 'application',
115115
schematics: {
116116
'@schematics/angular:component': {
117-
style: 'css'
117+
style: 'css',
118+
type: 'component'
119+
},
120+
'@schematics/angular:service': {
121+
type: 'service'
122+
},
123+
'@schematics/angular:pipe': {
124+
typeSeparator: '.'
125+
},
126+
'@schematics/angular:guard': {
127+
typeSeparator: '.'
118128
}
119129
},
120130
root: '',
@@ -167,8 +177,8 @@ export abstract class FileMockUtilities {
167177
'\tselector: \'app-root\',',
168178
'\tstandalone: true,',
169179
'\timports: [RouterOutlet],',
170-
'\ttemplateUrl: \'./app.component.html\',',
171-
'\tstyleUrl: \'./app.component.css\'',
180+
'\ttemplateUrl: \'./app.html\',',
181+
'\tstyleUrl: \'./app.css\'',
172182
'})',
173183
'export class AppComponent {}'
174184
], true, false);

src/angular/angular-json.model.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ interface AngularJsonSchematicOptions {
152152
* Style for the schematic.
153153
*/
154154
style?: 'css' | 'scss' | 'sass' | 'less',
155+
/**
156+
* The type of the schematic.
157+
*/
158+
type?: 'component' | 'service' | 'directive',
159+
/**
160+
* The separator for the filename.
161+
*/
162+
typeSeparator?: string,
155163
/**
156164
* Whether or not to use inlineTemplates.
157165
*/

src/angular/angular-utilities.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ describe('AngularUtilities', () => {
4242
' selector: \'app-root\',',
4343
' standalone: true,',
4444
` imports: [RouterOutlet, ${def.element}],`,
45-
' templateUrl: \'./app.component.html\',',
46-
' styleUrl: \'./app.component.css\'',
45+
' templateUrl: \'./app.html\',',
46+
' styleUrl: \'./app.css\'',
4747
'})',
4848
'export class AppComponent {}'
4949
]);
@@ -75,8 +75,8 @@ describe('AngularUtilities', () => {
7575
' selector: \'app-root\',',
7676
' standalone: true,',
7777
' imports: [RouterOutlet, NgxMatNavigationNavbarComponent, NgxMatNavigationFooterComponent],',
78-
' templateUrl: \'./app.component.html\',',
79-
' styleUrl: \'./app.component.css\'',
78+
' templateUrl: \'./app.html\',',
79+
' styleUrl: \'./app.css\'',
8080
'})',
8181
'export class AppComponent {',
8282
' navbarRows: NavbarRow[] = navbarRows;',
@@ -325,7 +325,7 @@ describe('AngularUtilities', () => {
325325
await AngularUtilities.setupPwa(mockConstants.ANGULAR_APP_DIR, mockConstants.ANGULAR_APP_NAME);
326326

327327
expect(cpExecSyncMock).toHaveBeenCalledTimes(1);
328-
expect(cpExecSyncMock).toHaveBeenCalledWith(`cd ${mockConstants.ANGULAR_APP_DIR} && npx @angular/cli@18 add @angular/pwa@18 --skip-confirmation`);
328+
expect(cpExecSyncMock).toHaveBeenCalledWith(`cd ${mockConstants.ANGULAR_APP_DIR} && npx @angular/cli@20 add @angular/pwa@20 --skip-confirmation`);
329329
expect(npmInstallMock).toHaveBeenCalledTimes(1);
330330
expect(npmInstallMock).toHaveBeenCalledWith(mockConstants.ANGULAR_APP_NAME, ['ngx-pwa']);
331331

@@ -342,8 +342,8 @@ describe('AngularUtilities', () => {
342342
' selector: \'app-root\',',
343343
' standalone: true,',
344344
' imports: [RouterOutlet, NgxPwaOfflineStatusBarComponent],',
345-
' templateUrl: \'./app.component.html\',',
346-
' styleUrl: \'./app.component.css\'',
345+
' templateUrl: \'./app.html\',',
346+
' styleUrl: \'./app.css\'',
347347
'})',
348348
'export class AppComponent {}'
349349
]);

src/angular/angular.utilities.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,15 @@ type NewOptions = {
6262
/**
6363
* Whether or not to use inline styles instead of a whole css file for each component.
6464
*/
65-
'--inline-style'?: boolean
65+
'--inline-style'?: boolean,
66+
/**
67+
* Whether or not to configure some ai.
68+
*/
69+
'--ai-config': 'none',
70+
/**
71+
* Whether or not to use zoneless change detection.
72+
*/
73+
'--zoneless': false
6674
};
6775

6876
/**
@@ -103,7 +111,7 @@ type AngularCliOptions<T extends AngularCliCommands> =
103111
*/
104112
export abstract class AngularUtilities {
105113

106-
private static readonly CLI_VERSION: number = 18;
114+
private static readonly CLI_VERSION: number = 20;
107115

108116
/**
109117
* Sets up logging.
@@ -454,14 +462,14 @@ export abstract class AngularUtilities {
454462
* @param root - The root of the angular project to setup material for.
455463
*/
456464
static async setupMaterial(root: string): Promise<void> {
457-
await Promise.all([
458-
this.addProvider(
459-
root,
460-
'provideAnimations()',
461-
[{ defaultImport: false, element: 'provideAnimations', path: '@angular/platform-browser/animations' }]
462-
),
463-
FsUtilities.updateFile(getPath(root, 'src', 'styles.css'), [
464-
'@import "@angular/material/prebuilt-themes/indigo-pink.css";',
465+
await this.addProvider(
466+
root,
467+
'provideAnimations()',
468+
[{ defaultImport: false, element: 'provideAnimations', path: '@angular/platform-browser/animations' }]
469+
);
470+
await FsUtilities.updateFile(
471+
getPath(root, 'src', 'styles.css'),
472+
[
465473
'',
466474
'html,',
467475
'body {',
@@ -473,8 +481,14 @@ export abstract class AngularUtilities {
473481
'\tmargin: 0;',
474482
'\tfont-family: Arial, Helvetica, sans-serif;',
475483
'}'
476-
], 'append')
477-
]);
484+
],
485+
'append'
486+
);
487+
await FsUtilities.updateFile(
488+
getPath(root, 'src', 'styles.css'),
489+
'\'@import "@angular/material/prebuilt-themes/indigo-pink.css";\'',
490+
'prepend'
491+
);
478492
}
479493

480494
/**
@@ -671,7 +685,7 @@ export abstract class AngularUtilities {
671685

672686
await NpmUtilities.install(name, [NpmPackage.NGX_MATERIAL_NAVIGATION]);
673687
await FsUtilities.updateFile(
674-
getPath(root, 'src', 'app', 'app.component.html'),
688+
getPath(root, 'src', 'app', 'app.html'),
675689
[
676690
// eslint-disable-next-line stylistic/max-len
677691
'<ngx-mat-navigation-navbar [minHeight]="80" [minSidenavWidth]="\'30%\'" [minHeightOtherElements]="70" [navbarRows]="navbarRows">',
@@ -808,7 +822,7 @@ export abstract class AngularUtilities {
808822
await this.runCommand(root, `add @angular/pwa@${this.CLI_VERSION}`, { '--skip-confirmation': true });
809823
await NpmUtilities.install(name, [NpmPackage.NGX_PWA]);
810824
await FsUtilities.updateFile(
811-
getPath(root, 'src', 'app', 'app.component.html'),
825+
getPath(root, 'src', 'app', 'app.html'),
812826
['<ngx-pwa-offline-status-bar></ngx-pwa-offline-status-bar>'],
813827
'prepend'
814828
);

src/commands/add/add-angular-library/add-angular-library.command.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AngularUtilities } from '../../../angular';
2-
import { ANGULAR_JSON_FILE_NAME, BASE_TS_CONFIG_FILE_NAME, GIT_IGNORE_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME } from '../../../constants';
2+
import { ANGULAR_JSON_FILE_NAME, BASE_TS_CONFIG_FILE_NAME, ESLINT_CONFIG_FILE_NAME, GIT_IGNORE_FILE_NAME, LIBS_DIRECTORY_NAME, PACKAGE_JSON_FILE_NAME } from '../../../constants';
33
import { FsUtilities, JsonUtilities, QuestionsFor } from '../../../encapsulation';
44
import { EslintUtilities } from '../../../eslint';
55
import { NpmUtilities, PackageJson } from '../../../npm';
@@ -50,7 +50,7 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
5050
override async run(): Promise<void> {
5151
const config: AddAngularLibraryConfiguration = await this.getConfig();
5252
const result: CreateResult = await this.createProject(config);
53-
53+
await EslintUtilities.setupProjectEslint(result.root, false);
5454
await Promise.all([
5555
FsUtilities.rm(getPath(result.root, '.vscode')),
5656
FsUtilities.rm(getPath(result.root, '.editorconfig')),
@@ -61,10 +61,22 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
6161
this.updateAngularJson(result.root, config.name),
6262
this.setupTsConfig(result.root, config),
6363
this.updatePackageJson(result, config.name),
64-
this.setupTailwind(result.root),
65-
EslintUtilities.setupProjectEslint(result.root, false)
64+
this.setupTailwind(result.root)
6665
]);
6766
await FsUtilities.rm(getPath(result.root, 'projects'));
67+
await FsUtilities.replaceInFile(
68+
getPath(result.root, ESLINT_CONFIG_FILE_NAME),
69+
' ...baseConfig,',
70+
[
71+
' ...baseConfig,',
72+
' {',
73+
' files: [\'**/*.stories.ts\'],',
74+
' rules: {',
75+
' \'jsdoc/require-jsdoc\': \'off\'',
76+
' }',
77+
' }'
78+
].join('\n')
79+
);
6880
}
6981

7082
private async updatePublicApi(root: string): Promise<void> {
@@ -94,7 +106,7 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
94106
await AngularUtilities.runCommand(
95107
getPath(LIBS_DIRECTORY_NAME),
96108
`new ${config.name}`,
97-
{ '--no-create-application': true }
109+
{ '--no-create-application': true, '--ai-config': 'none', '--zoneless': false }
98110
);
99111
// eslint-disable-next-line no-console
100112
console.log('Creates the base library');
@@ -140,6 +152,30 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
140152
await FsUtilities.replaceInFile(getPath(LIBS_DIRECTORY_NAME, config.name, ANGULAR_JSON_FILE_NAME), '"root": ,', '"root": "./",');
141153

142154
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
155+
await AngularUtilities.updateAngularJson(
156+
getPath(newProject.path, ANGULAR_JSON_FILE_NAME),
157+
{
158+
projects: {
159+
[newProject.name]: {
160+
schematics: {
161+
'@schematics/angular:component': {
162+
style: 'css',
163+
type: 'component'
164+
},
165+
'@schematics/angular:service': {
166+
type: 'service'
167+
},
168+
'@schematics/angular:pipe': {
169+
typeSeparator: '.'
170+
},
171+
'@schematics/angular:guard': {
172+
typeSeparator: '.'
173+
}
174+
}
175+
}
176+
}
177+
}
178+
);
143179
await FsUtilities.rm(getPath(newProject.path, 'src', 'stories', '.eslintrc.json'));
144180
return { root: newProject.path, oldPackageJson };
145181
}
@@ -201,7 +237,8 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
201237
files: ['src/public-api.ts'],
202238
include: [
203239
'src/**/*.spec.ts',
204-
'src/**/*.d.ts'
240+
'src/**/*.d.ts',
241+
'src/**/*.stories.ts'
205242
]
206243
};
207244
await FsUtilities.createFile(getPath(root, 'tsconfig.eslint.json'), JsonUtilities.stringify(eslintTsconfig));
@@ -244,6 +281,11 @@ export class AddAngularLibraryCommand extends BaseAddCommand<AddAngularLibraryCo
244281
options: {
245282
tsConfig: 'tsconfig.spec.json'
246283
}
284+
},
285+
storybook: {
286+
options: {
287+
styles: ['src/styles.css']
288+
}
247289
}
248290
}
249291
}

src/commands/add/add-angular-website/add-angular-website.command.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { AngularUtilities, NavElementTypes } from '../../../angular';
2-
import { ANGULAR_JSON_FILE_NAME, APPS_DIRECTORY_NAME, BASE_TS_CONFIG_FILE_NAME, DOCKER_FILE_NAME, GIT_IGNORE_FILE_NAME } from '../../../constants';
2+
import { ANGULAR_APP_COMPONENT_FILE_NAME, ANGULAR_JSON_FILE_NAME, APPS_DIRECTORY_NAME, BASE_TS_CONFIG_FILE_NAME, DOCKER_FILE_NAME, GIT_IGNORE_FILE_NAME } from '../../../constants';
33
import { DockerUtilities } from '../../../docker';
44
import { FsUtilities, JsonUtilities, QuestionsFor } from '../../../encapsulation';
55
import { DefaultEnvKeys, EnvUtilities } from '../../../env';
@@ -82,7 +82,7 @@ export class AddAngularWebsiteCommand extends BaseAddCommand<AddAngularWebsiteCo
8282

8383
await AngularUtilities.addSitemapAndRobots(root, config.name, domain);
8484

85-
await this.cleanUp(root);
85+
await this.cleanUp(root, config.name);
8686
await this.setupTsConfig(root, config.name);
8787
await this.createDockerfile(root, config);
8888
await AngularUtilities.setupNavigation(root, config.name);
@@ -222,13 +222,23 @@ export class AddAngularWebsiteCommand extends BaseAddCommand<AddAngularWebsiteCo
222222
await FsUtilities.createFile(getPath(root, 'tsconfig.eslint.json'), JsonUtilities.stringify(eslintTsconfig));
223223
}
224224

225-
private async cleanUp(root: string): Promise<void> {
225+
private async cleanUp(root: string, name: string): Promise<void> {
226226
// eslint-disable-next-line no-console
227227
console.log('cleans up');
228+
await FsUtilities.replaceInFile(
229+
getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME),
230+
`protected readonly title = signal('${name}');`,
231+
' constructor() {}'
232+
);
233+
await FsUtilities.replaceInFile(
234+
getPath(root, 'src', 'app', ANGULAR_APP_COMPONENT_FILE_NAME),
235+
'Component, signal',
236+
'Component'
237+
);
228238
await FsUtilities.rm(getPath(root, '.vscode'));
229239
await FsUtilities.rm(getPath(root, '.editorconfig'));
230240
await FsUtilities.rm(getPath(root, GIT_IGNORE_FILE_NAME));
231-
await FsUtilities.rm(getPath(root, 'src', 'app', 'app.component.spec.ts'));
241+
await FsUtilities.rm(getPath(root, 'src', 'app', 'app.spec.ts'));
232242
}
233243

234244
private async createProject(config: AddAngularWebsiteConfiguration): Promise<Path> {
@@ -237,10 +247,34 @@ export class AddAngularWebsiteCommand extends BaseAddCommand<AddAngularWebsiteCo
237247
await AngularUtilities.runCommand(
238248
getPath(APPS_DIRECTORY_NAME),
239249
`new ${config.name}`,
240-
{ '--skip-git': true, '--style': 'css', '--inline-style': true, '--ssr': true }
250+
{ '--skip-git': true, '--style': 'css', '--inline-style': true, '--ssr': true, '--ai-config': 'none', '--zoneless': false }
241251
);
242252
const newProject: WorkspaceProject = await WorkspaceUtilities.findProjectOrFail(config.name, getPath('.'));
243-
await FsUtilities.updateFile(getPath(newProject.path, 'src', 'app', 'app.component.html'), '', 'replace');
253+
await AngularUtilities.updateAngularJson(
254+
getPath(newProject.path, ANGULAR_JSON_FILE_NAME),
255+
{
256+
projects: {
257+
[newProject.name]: {
258+
schematics: {
259+
'@schematics/angular:component': {
260+
style: 'css',
261+
type: 'component'
262+
},
263+
'@schematics/angular:service': {
264+
type: 'service'
265+
},
266+
'@schematics/angular:pipe': {
267+
typeSeparator: '.'
268+
},
269+
'@schematics/angular:guard': {
270+
typeSeparator: '.'
271+
}
272+
}
273+
}
274+
}
275+
}
276+
);
277+
await FsUtilities.updateFile(getPath(newProject.path, 'src', 'app', 'app.html'), '', 'replace');
244278
await AngularUtilities.addProvider(newProject.path, 'provideHttpClient(withInterceptorsFromDi(), withFetch())', [
245279
// eslint-disable-next-line sonar/no-duplicate-string
246280
{ defaultImport: false, element: 'provideHttpClient', path: '@angular/common/http' },

0 commit comments

Comments
 (0)