@dsivd/prestations-ng 19.2.0-beta.3 → 19.2.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/CONTRIBUTING.md +40 -1
- package/GOOD_PRACTICES.md +156 -29
- package/UPGRADING_V19.md +166 -0
- package/dsivd-prestations-ng-19.2.0-beta.5.tgz +0 -0
- package/eslint/configs/template-recommended.mjs +2 -0
- package/eslint/configs/template-rules.mjs +6 -2
- package/eslint/configs/ts-recommended.mjs +2 -0
- package/eslint/configs/ts-rules.mjs +6 -2
- package/fesm2022/dsivd-prestations-ng.mjs +1197 -932
- package/fesm2022/dsivd-prestations-ng.mjs.map +1 -1
- package/package.json +1 -2
- package/schematics/ng-add/index.js +2 -4
- package/schematics/ng-update/migrations/update-13_2_0/index.js +7 -2
- package/schematics/utility/add-allowed-common-js-dependencies.js +39 -29
- package/schematics/utility/remove-emit-decorator-metadata.js +8 -9
- package/src/eslint/configs/template-recommended.mjs +2 -0
- package/src/eslint/configs/template-rules.mjs +6 -2
- package/src/eslint/configs/ts-recommended.mjs +2 -0
- package/src/eslint/configs/ts-rules.mjs +6 -2
- package/types/dsivd-prestations-ng.d.ts +222 -128
- package/dsivd-prestations-ng-19.2.0-beta.3.tgz +0 -0
package/UPGRADING_V19.md
CHANGED
|
@@ -1449,6 +1449,172 @@ npm run test
|
|
|
1449
1449
|
npm start
|
|
1450
1450
|
```
|
|
1451
1451
|
|
|
1452
|
+
### `foehn-list-summary` is now generic (since 19.2.0)
|
|
1453
|
+
|
|
1454
|
+
`FoehnListSummaryComponent` is now `FoehnListSummaryComponent<T extends FoehnListItem>` and `FoehnListItemDescription` now takes a type parameter: `FoehnListItemDescription<T>`.
|
|
1455
|
+
Using `FoehnListItemDescription` without its type parameter no longer compiles.
|
|
1456
|
+
|
|
1457
|
+
Replace every `FoehnListItemDescription` with `FoehnListItemDescription<MyItem>`, where `MyItem` is your class extending `FoehnListItem`. You can then drop the casts (or `any`) in `getFormattedValue` and `hideIfEmpty`:
|
|
1458
|
+
|
|
1459
|
+
Before:
|
|
1460
|
+
|
|
1461
|
+
```typescript
|
|
1462
|
+
getListItemsDescription(): FoehnListItemDescription[] {
|
|
1463
|
+
return [
|
|
1464
|
+
{
|
|
1465
|
+
label: 'Name',
|
|
1466
|
+
getFormattedValue: (item: FoehnListItem) =>
|
|
1467
|
+
(item as MyItem).name ?? '',
|
|
1468
|
+
},
|
|
1469
|
+
];
|
|
1470
|
+
}
|
|
1471
|
+
```
|
|
1472
|
+
|
|
1473
|
+
After:
|
|
1474
|
+
|
|
1475
|
+
```typescript
|
|
1476
|
+
getListItemsDescription(): FoehnListItemDescription<MyItem>[] {
|
|
1477
|
+
return [
|
|
1478
|
+
{
|
|
1479
|
+
label: 'Name',
|
|
1480
|
+
getFormattedValue: (item: MyItem) => item.name ?? '',
|
|
1481
|
+
},
|
|
1482
|
+
];
|
|
1483
|
+
}
|
|
1484
|
+
```
|
|
1485
|
+
|
|
1486
|
+
The same applies to the function passed to `getListItemTitle`, which now receives a `MyItem`.
|
|
1487
|
+
|
|
1488
|
+
### `core-js` is no longer needed (since 19.2.0)
|
|
1489
|
+
|
|
1490
|
+
prestations-ng no longer imports `core-js` and no longer has it as a peer dependency. If your project does not
|
|
1491
|
+
import `core-js` itself, uninstall it:
|
|
1492
|
+
|
|
1493
|
+
```bash
|
|
1494
|
+
npm uninstall core-js
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
Then, in your `angular.json` file, remove `"core-js/modules/es.array.includes"` from `"allowedCommonJsDependencies"`.
|
|
1498
|
+
The CommonJS dependencies of prestations-ng are now `"iban"` and `"dayjs"` (which also covers `dayjs/plugin/*` and
|
|
1499
|
+
`dayjs/locale/*`):
|
|
1500
|
+
|
|
1501
|
+
```json
|
|
1502
|
+
"allowedCommonJsDependencies": ["iban", "dayjs"]
|
|
1503
|
+
```
|
|
1504
|
+
|
|
1505
|
+
### Zoneless (optional but recommended)
|
|
1506
|
+
|
|
1507
|
+
Since v19.2, prestations-ng does not need zone.js anymore: the state of its components is held by signals, which
|
|
1508
|
+
tell Angular when a component has to be refreshed. prestations-ng keeps working in an application using zone.js,
|
|
1509
|
+
so this step is optional, but a zoneless application is lighter, faster and easier to debug. See the
|
|
1510
|
+
[Angular zoneless guide](https://angular.dev/guide/zoneless).
|
|
1511
|
+
|
|
1512
|
+
In any case, if your code reads some fields of the prestations-ng components (e.g. through `viewChild()` or in
|
|
1513
|
+
your tests), check the fields that are now signals in the [CHANGELOG](CHANGELOG.md#1920---should-be-aligned-with-prestations-be-192x).
|
|
1514
|
+
|
|
1515
|
+
#### Enable the zoneless change detection
|
|
1516
|
+
|
|
1517
|
+
Zoneless is the default since Angular 21: `ng update` added `provideZoneChangeDetection()` to keep zone.js in your
|
|
1518
|
+
application. Replace it in your `app.config.ts` (`providePrestationsNgCore()` already provides
|
|
1519
|
+
`provideBrowserGlobalErrorListeners()`, which reports to your `ErrorHandler` the errors zone.js used to catch):
|
|
1520
|
+
|
|
1521
|
+
```diff
|
|
1522
|
+
export const appConfig: ApplicationConfig = {
|
|
1523
|
+
providers: [
|
|
1524
|
+
- provideZoneChangeDetection({ eventCoalescing: true }),
|
|
1525
|
+
+ provideZonelessChangeDetection(),
|
|
1526
|
+
providePrestationsNgCore(),
|
|
1527
|
+
...
|
|
1528
|
+
],
|
|
1529
|
+
};
|
|
1530
|
+
```
|
|
1531
|
+
|
|
1532
|
+
Remove `zone.js` and `zone.js/testing` from the `polyfills` of the `build` and `test` targets in your
|
|
1533
|
+
`angular.json` (and from your `polyfills.ts` file if you still have one): without them, the `TestBed` is zoneless
|
|
1534
|
+
too.
|
|
1535
|
+
|
|
1536
|
+
```diff
|
|
1537
|
+
"polyfills": [
|
|
1538
|
+
- "zone.js"
|
|
1539
|
+
],
|
|
1540
|
+
```
|
|
1541
|
+
|
|
1542
|
+
then uninstall zone.js:
|
|
1543
|
+
|
|
1544
|
+
```bash
|
|
1545
|
+
npm uninstall zone.js
|
|
1546
|
+
```
|
|
1547
|
+
|
|
1548
|
+
#### Check your components
|
|
1549
|
+
|
|
1550
|
+
Without zone.js, Angular refreshes a component only when it is notified that something changed:
|
|
1551
|
+
|
|
1552
|
+
- a listener of its template has been called (`(click)`, `(modelChange)`, `(userInput)`...), including the
|
|
1553
|
+
`[(model)]` two-way bindings
|
|
1554
|
+
- a signal read by its template has changed (`signal()`, `computed()`, `input()`, `model()`, `toSignal()`...)
|
|
1555
|
+
- `ChangeDetectorRef.markForCheck()` has been called, which is what the `async` pipe does when an observable emits
|
|
1556
|
+
|
|
1557
|
+
A field modified elsewhere (in a `subscribe()`, a `setTimeout()`, a `Promise`, a callback...) is not displayed
|
|
1558
|
+
anymore until something else refreshes the component. Hold it in a signal (see
|
|
1559
|
+
[INTRODUCTION_ANGULAR_SIGNALS.md](INTRODUCTION_ANGULAR_SIGNALS.md)):
|
|
1560
|
+
|
|
1561
|
+
```diff
|
|
1562
|
+
- isLoading = true;
|
|
1563
|
+
+ readonly isLoading = signal(true);
|
|
1564
|
+
|
|
1565
|
+
ngOnInit(): void {
|
|
1566
|
+
this.myService.load().subscribe(() => {
|
|
1567
|
+
- this.isLoading = false;
|
|
1568
|
+
+ this.isLoading.set(false);
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
```
|
|
1572
|
+
|
|
1573
|
+
```diff
|
|
1574
|
+
- @if (isLoading) {
|
|
1575
|
+
+ @if (isLoading()) {
|
|
1576
|
+
```
|
|
1577
|
+
|
|
1578
|
+
Pay attention to:
|
|
1579
|
+
|
|
1580
|
+
- your pages (`AbstractPageComponent` and its subclasses): prestations-ng refreshes them when it sets `form` and
|
|
1581
|
+
`reference`. But if you modify the form yourself in an asynchronous callback, e.g. the one given to
|
|
1582
|
+
`SessionInfoWithApplicationService.prefillForm()` or a `subscribe()` of your own service, call
|
|
1583
|
+
`markForCheck()` afterwards:
|
|
1584
|
+
|
|
1585
|
+
```ts
|
|
1586
|
+
private readonly changeDetectorRef = inject(ChangeDetectorRef);
|
|
1587
|
+
|
|
1588
|
+
ngOnInit(): void {
|
|
1589
|
+
super.ngOnInit();
|
|
1590
|
+
this.sessionInfoWithApplicationService.prefillForm((info) => {
|
|
1591
|
+
this.form.email = info?.email ?? null;
|
|
1592
|
+
this.changeDetectorRef.markForCheck();
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
```
|
|
1596
|
+
|
|
1597
|
+
- `NgZone`: `onStable`, `onMicrotaskEmpty` and `onUnstable` never emit without zone.js, and `run()` or
|
|
1598
|
+
`runOutsideAngular()` are useless. To act on the rendered DOM (focus, scroll...), replace them, as well as the
|
|
1599
|
+
`setTimeout()` waiting for the view, by `afterNextRender()`. `AbstractMenuPageComponent.ngZone` is deprecated.
|
|
1600
|
+
|
|
1601
|
+
```diff
|
|
1602
|
+
- this.ngZone.onStable.pipe(first()).subscribe(() => this.focusFirstField());
|
|
1603
|
+
+ afterNextRender(() => this.focusFirstField(), { injector: this.injector });
|
|
1604
|
+
```
|
|
1605
|
+
|
|
1606
|
+
#### Check your tests
|
|
1607
|
+
|
|
1608
|
+
- `fakeAsync()`, `tick()`, `flush()` and `waitForAsync()` need zone.js: write `async` tests, with
|
|
1609
|
+
`vi.useFakeTimers()` and `await vi.advanceTimersByTimeAsync(ms)` to control the timers (see
|
|
1610
|
+
[Migrate to vitest](#migrate-to-vitest)).
|
|
1611
|
+
- `fixture.detectChanges()` only refreshes the views which have been notified, then checks that nothing changed
|
|
1612
|
+
meanwhile: a field modified without notification makes the test fail with the error `NG0100`
|
|
1613
|
+
(`ExpressionChangedAfterItHasBeenCheckedError`). Fix the component (signal, `markForCheck()`) rather than the
|
|
1614
|
+
test.
|
|
1615
|
+
- `await fixture.whenStable()` waits for the change detection and for the pending tasks of the application
|
|
1616
|
+
(e.g. the debounced `userInput` of the prestations-ng inputs), not for the timers.
|
|
1617
|
+
|
|
1452
1618
|
### Last but not least, check if your application is working!!!
|
|
1453
1619
|
|
|
1454
1620
|
#### Be sure your application gets a fresh start
|
|
Binary file
|
|
@@ -8,6 +8,8 @@ import templateRules from './template-rules.mjs';
|
|
|
8
8
|
*
|
|
9
9
|
* Meant for the `extends` of a `**\/*.html` block. It brings its own parser and plugins,
|
|
10
10
|
* so do not spread `angular.configs.templateRecommended` alongside it.
|
|
11
|
+
*
|
|
12
|
+
* @returns {import('typescript-eslint').ConfigArray}
|
|
11
13
|
*/
|
|
12
14
|
const templateRecommended = (plugin) => [
|
|
13
15
|
...angular.configs.templateRecommended,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import templateBase from './template-base.mjs';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Only the rules written by this library. `templateRecommended` includes it, alongside
|
|
5
|
+
* the house style; use this layer directly to opt out of the latter.
|
|
6
|
+
*
|
|
7
|
+
* @returns {import('typescript-eslint').ConfigArray}
|
|
8
|
+
*/
|
|
5
9
|
const templateRules = (plugin) => [
|
|
6
10
|
templateBase(plugin),
|
|
7
11
|
{
|
|
@@ -14,6 +14,8 @@ import tsRules from './ts-rules.mjs';
|
|
|
14
14
|
* Meant for the `extends` of a `**\/*.ts` block. It brings its own parser and plugins,
|
|
15
15
|
* so do not spread `angular.configs.tsRecommended` alongside it — declaring the same
|
|
16
16
|
* plugin twice from two different copies makes ESLint fail outright.
|
|
17
|
+
*
|
|
18
|
+
* @returns {import('typescript-eslint').ConfigArray}
|
|
17
19
|
*/
|
|
18
20
|
const tsRecommended = (plugin) => [
|
|
19
21
|
eslint.configs.recommended,
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import tsBase from './ts-base.mjs';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Only the rules written by this library. `tsRecommended` includes it, alongside the
|
|
5
|
+
* house style; use this layer directly to opt out of the latter.
|
|
6
|
+
*
|
|
7
|
+
* @returns {import('typescript-eslint').ConfigArray}
|
|
8
|
+
*/
|
|
5
9
|
const tsRules = (plugin) => [
|
|
6
10
|
tsBase(plugin),
|
|
7
11
|
{
|