chore(deps): update npm packages within declared ranges; reformat for prettier 3.9.4
Some checks failed
CI / frontend (push) Successful in 1m46s
CI / storybook-a11y (push) Successful in 4m23s
CI / backend (push) Successful in 1m14s
CI / codeql (csharp) (push) Has been cancelled
CI / codeql (javascript-typescript) (push) Has been cancelled
CI / api-client-drift (push) Has been cancelled
CI / e2e (push) Has been cancelled
Some checks failed
CI / frontend (push) Successful in 1m46s
CI / storybook-a11y (push) Successful in 4m23s
CI / backend (push) Successful in 1m14s
CI / codeql (csharp) (push) Has been cancelled
CI / codeql (javascript-typescript) (push) Has been cancelled
CI / api-client-drift (push) Has been cancelled
CI / e2e (push) Has been cancelled
npm update brought every package to the latest version its existing package.json range allows (Angular tooling 22.0.2/22.0.4 -> 22.0.5, prettier 3.8.4 -> 3.9.4, typescript-eslint 8.62.0 -> 8.62.1); package.json itself needed no range changes. Auditing actual deprecation warnings (not just outdated versions) found nothing further to fix: @angular/platform-browser-dynamic and @angular-devkit/build-angular are deprecated by Angular but still required peer dependencies of the latest published @storybook/angular (10.4.6 — peer range still `>=18.0.0 < 22.0.0`, already why .npmrc sets legacy-peer-deps); jest-process-manager/expect-playwright are transitive-only through @storybook/test-runner's latest stable (0.24.4). No newer version of either Storybook package exists yet that drops them. The remaining npm audit advisory (@babel/core, low severity) is the same already-documented, deliberately-left issue in README.md (fixing it downgrades Angular). Left package.json's overrides untouched. The prettier bump alone changed formatting opinions on files this session didn't otherwise touch (a stale markdown italics marker, a few object-literal wrap points) — reformatted everything so `format:check` (part of CI) doesn't regress. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -82,7 +82,7 @@ model a discriminated union instead.** Three tools, all in `shared/application`:
|
||||
machine's State/Msg types are context-prefixed (`ChangeRequestState`,
|
||||
`ChangeRequestMsg`), never bare `State`/`Msg`; a top-level machine exports
|
||||
`initial` + `reduce`. A **composable sub-machine** embedded inside a parent
|
||||
model keeps prefixed *value* exports instead (`initialUpload`/`reduceUpload`,
|
||||
model keeps prefixed _value_ exports instead (`initialUpload`/`reduceUpload`,
|
||||
see `upload.machine.ts`) — prefixing there avoids alias noise at the
|
||||
composition site.
|
||||
- **`Result<E,T>` + value objects** ("parse, don't validate") — raw input becomes a
|
||||
|
||||
@@ -4,7 +4,7 @@ Status: done (69880ef)
|
||||
Phase: 2 — CIBG fidelity
|
||||
|
||||
> **Deviation:** file-input's label-button was already reworked to `.btn-primary
|
||||
> .btn-upload` by the earlier out-of-order "CIBG UI fidelity pass" (WP-11/12) — the
|
||||
.btn-upload` by the earlier out-of-order "CIBG UI fidelity pass" (WP-11/12) — the
|
||||
> vendored upload vocabulary (`.btn-upload`) supersedes this WP's original
|
||||
> `.btn-secondary` assumption, so no change was needed there. Icon affordances
|
||||
> (chevron/pijl classes) are verified present in the vendored CSS, but no in-scope
|
||||
|
||||
4235
package-lock.json
generated
4235
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -79,7 +79,10 @@ describe('BriefStore action state (Idle | Busy | Failed)', () => {
|
||||
|
||||
approveResult = {
|
||||
ok: true,
|
||||
value: { ...view, brief: { ...brief, status: { tag: 'approved', approvedBy: 'u2', approvedAt: 't' } } },
|
||||
value: {
|
||||
...view,
|
||||
brief: { ...brief, status: { tag: 'approved', approvedBy: 'u2', approvedAt: 't' } },
|
||||
},
|
||||
};
|
||||
await store.approve();
|
||||
expect(store.busy()).toBe(false);
|
||||
|
||||
@@ -8,10 +8,16 @@ import { parsePostcode } from '@registratie/domain/value-objects/postcode';
|
||||
const postcode = parsePostcode('2514 EA');
|
||||
if (!postcode.ok) throw new Error('fixture postcode should parse');
|
||||
|
||||
const data: Valid = { straat: 'Lange Voorhout 9', postcode: postcode.value, woonplaats: 'Den Haag' };
|
||||
const data: Valid = {
|
||||
straat: 'Lange Voorhout 9',
|
||||
postcode: postcode.value,
|
||||
woonplaats: 'Den Haag',
|
||||
};
|
||||
|
||||
function setup(adapter: Partial<ChangeRequestAdapter>) {
|
||||
TestBed.configureTestingModule({ providers: [{ provide: ChangeRequestAdapter, useValue: adapter }] });
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{ provide: ChangeRequestAdapter, useValue: adapter }],
|
||||
});
|
||||
return TestBed.runInInjectionContext(() => createSubmitChangeRequest());
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ describe('change-request reduce', () => {
|
||||
it('SetField updates the draft while editing', () => {
|
||||
const s = reduce(initial, { tag: 'SetField', key: 'straat', value: 'Lange Voorhout 9' });
|
||||
expect(s.tag).toBe('Editing');
|
||||
expect((s as Extract<ChangeRequestState, { tag: 'Editing' }>).draft.straat).toBe('Lange Voorhout 9');
|
||||
expect((s as Extract<ChangeRequestState, { tag: 'Editing' }>).draft.straat).toBe(
|
||||
'Lange Voorhout 9',
|
||||
);
|
||||
});
|
||||
|
||||
it('Submit with an invalid draft stays Editing and reports field errors', () => {
|
||||
|
||||
@@ -3,7 +3,9 @@ import { parseAantekening } from './big-register.adapter';
|
||||
|
||||
describe('big-register.adapter parse boundary', () => {
|
||||
it('parses known aantekening types', () => {
|
||||
expect(parseAantekening({ type: 'Specialisme', omschrijving: 'x', datum: '2026-01-01' })).toEqual({
|
||||
expect(
|
||||
parseAantekening({ type: 'Specialisme', omschrijving: 'x', datum: '2026-01-01' }),
|
||||
).toEqual({
|
||||
ok: true,
|
||||
value: { type: 'Specialisme', omschrijving: 'x', datum: '2026-01-01' },
|
||||
});
|
||||
|
||||
@@ -10,7 +10,12 @@ import {
|
||||
} from '@registratie/ui/address-fields/address-fields.component';
|
||||
import { createStore } from '@shared/application/store';
|
||||
import { whenTag } from '@shared/kernel/fp';
|
||||
import { ChangeRequestState, ChangeRequestMsg, initial, reduce } from '@registratie/domain/change-request.machine';
|
||||
import {
|
||||
ChangeRequestState,
|
||||
ChangeRequestMsg,
|
||||
initial,
|
||||
reduce,
|
||||
} from '@registratie/domain/change-request.machine';
|
||||
import { createSubmitChangeRequest } from '@registratie/application/submit-change-request';
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,8 +12,7 @@ export function assertNever(x: never): never {
|
||||
/** A computation that either succeeded with a value or failed with an error.
|
||||
Plain objects (no classes) to match the signal/httpResource ergonomics. */
|
||||
export type Result<E, T> =
|
||||
| { readonly ok: true; readonly value: T }
|
||||
| { readonly ok: false; readonly error: E };
|
||||
{ readonly ok: true; readonly value: T } | { readonly ok: false; readonly error: E };
|
||||
|
||||
export const ok = <T>(value: T): Result<never, T> => ({ ok: true, value });
|
||||
export const err = <E>(error: E): Result<E, never> => ({ ok: false, error });
|
||||
|
||||
@@ -19,8 +19,7 @@ const meta: Meta<WizardShellComponent> = {
|
||||
cibgGap: true,
|
||||
docs: {
|
||||
description: {
|
||||
component:
|
||||
'CIBG-gap extension (error summary only) — see Foundations/CIBG Gap Register.',
|
||||
component: 'CIBG-gap extension (error summary only) — see Foundations/CIBG Gap Register.',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -245,10 +245,7 @@ export class RichTextEditorComponent {
|
||||
}
|
||||
if (!(e.ctrlKey || e.metaKey) || e.altKey) return;
|
||||
const cmd = { b: 'bold', i: 'italic', u: 'underline' }[e.key.toLowerCase()] as
|
||||
| 'bold'
|
||||
| 'italic'
|
||||
| 'underline'
|
||||
| undefined;
|
||||
'bold' | 'italic' | 'underline' | undefined;
|
||||
if (!cmd) return;
|
||||
e.preventDefault();
|
||||
this.format(cmd);
|
||||
|
||||
@@ -83,8 +83,7 @@ export type UploadMsg =
|
||||
type: 'BackgroundUploadsReturned';
|
||||
results: Array<
|
||||
{ localId: string } & (
|
||||
| { success: true; documentId: string }
|
||||
| { success: false; reason: string }
|
||||
{ success: true; documentId: string } | { success: false; reason: string }
|
||||
)
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ placed above the `@Component` decorator, plus `parameters: { cibgGap: true }` an
|
||||
## The register
|
||||
|
||||
| Component | Closest CIBG concept | Why hand-rolled |
|
||||
| --- | --- | --- |
|
||||
| --------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `skeleton` | Laadindicatie | No loading-skeleton class in the vendored build. |
|
||||
| `spinner` | Laadindicatie | No loading-spinner class in the vendored build. |
|
||||
| `rich-text-editor` | Tekstgebied | No rich-text/WYSIWYG pattern; toolbar buttons still use vendored `.btn-ghost` (WP-10). |
|
||||
|
||||
@@ -34,7 +34,7 @@ Never the other way — `registratie` may not import `herregistratie`, and no co
|
||||
## Five layers, one direction
|
||||
|
||||
| Layer | Job | Angular allowed? |
|
||||
| --- | --- | --- |
|
||||
| ----------------- | ----------------------------------------- | ----------------- |
|
||||
| `domain/` | business rules + data types | **No — pure TS.** |
|
||||
| `application/` | coordinate state/tasks (stores, commands) | yes (signals) |
|
||||
| `infrastructure/` | where data comes from (HTTP adapters) | yes (HTTP) |
|
||||
|
||||
@@ -36,7 +36,11 @@ dispatches a message describing the outcome:
|
||||
// command = "go do it, then say what happened" — reduce never sees the HTTP call itself
|
||||
async function submit(store: Store<WizardState, WizardMsg>) {
|
||||
const r = await adapter.submit(toDto(store.model()));
|
||||
store.dispatch(r.ok ? { tag: 'SubmitConfirmed', referentie: r.value } : { tag: 'SubmitFailed', error: r.error });
|
||||
store.dispatch(
|
||||
r.ok
|
||||
? { tag: 'SubmitConfirmed', referentie: r.value }
|
||||
: { tag: 'SubmitFailed', error: r.error },
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -60,7 +64,7 @@ worse name, and it's the thing a newcomer copies if two idioms are visible side
|
||||
Wire every machine through `createStore`, full stop.
|
||||
|
||||
`dispatch` uses `model.update(…)`, not `model.set(reduce(model(), msg))` — the latter
|
||||
reads `model()` *inside* the call, which means an `effect()` that both reads `model` and
|
||||
reads `model()` _inside_ the call, which means an `effect()` that both reads `model` and
|
||||
calls `dispatch` would subscribe to its own write and livelock. `.update()`'s callback
|
||||
receives the current value directly, untracked.
|
||||
|
||||
@@ -73,7 +77,7 @@ receives the current value directly, untracked.
|
||||
- A top-level machine exports `initial` (the starting Model) and `reduce` — unprefixed,
|
||||
since the file/module already disambiguates them at the import site
|
||||
(`import { initial, reduce } from './herregistratie.machine'`).
|
||||
- A **composable sub-machine** — one embedded *inside* a parent Model, like
|
||||
- A **composable sub-machine** — one embedded _inside_ a parent Model, like
|
||||
`upload.machine.ts`'s upload-widget state living inside the registratie wizard's own
|
||||
Model — keeps **prefixed value exports** instead: `initialUpload`, `reduceUpload`.
|
||||
The parent machine already imports several machines' `initial`/`reduce`; prefixing the
|
||||
@@ -90,7 +94,7 @@ a function of what I already have?"
|
||||
## Where RemoteData fits in
|
||||
|
||||
A machine owns the **domain** lifecycle of what it holds once it exists (draft →
|
||||
submitted → approved, in the brief's case). It should generally *not* also own the
|
||||
submitted → approved, in the brief's case). It should generally _not_ also own the
|
||||
**fetch** lifecycle (loading/failed) for the initial GET that produces it — that's a
|
||||
generic concern `RemoteData` already models once, consistently, across the app (see
|
||||
[Foundations/RemoteData & Async](?path=/docs/foundations-remotedata-async--docs)). Where
|
||||
|
||||
@@ -37,7 +37,11 @@ enters.
|
||||
```ts
|
||||
// before — the wire's `type` string is trusted outright
|
||||
function toAantekening(n: AantekeningDto): Aantekening {
|
||||
return { type: n.type as AantekeningType, omschrijving: n.omschrijving ?? '', datum: n.datum ?? '' };
|
||||
return {
|
||||
type: n.type as AantekeningType,
|
||||
omschrijving: n.omschrijving ?? '',
|
||||
datum: n.datum ?? '',
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
@@ -48,7 +52,11 @@ const AANTEKENING_TYPES: readonly AantekeningType[] = ['Specialisme', 'Aantekeni
|
||||
export function parseAantekening(n: AantekeningDto): Result<string, Aantekening> {
|
||||
if (!n.type || !AANTEKENING_TYPES.includes(n.type as AantekeningType))
|
||||
return err(`aantekening: unknown type ${n.type}`);
|
||||
return ok({ type: n.type as AantekeningType, omschrijving: n.omschrijving ?? '', datum: n.datum ?? '' });
|
||||
return ok({
|
||||
type: n.type as AantekeningType,
|
||||
omschrijving: n.omschrijving ?? '',
|
||||
datum: n.datum ?? '',
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
@@ -86,7 +94,9 @@ policyResource() {
|
||||
|
||||
```ts
|
||||
// after — a domain-side type + a validated parse; the resource never surfaces raw wire shape
|
||||
export interface IntakePolicy { readonly scholingThreshold: number }
|
||||
export interface IntakePolicy {
|
||||
readonly scholingThreshold: number;
|
||||
}
|
||||
|
||||
export function parseIntakePolicy(json: unknown): Result<string, IntakePolicy> {
|
||||
if (typeof json !== 'object' || json === null) return err('intake-policy: not an object');
|
||||
@@ -99,7 +109,7 @@ export function parseIntakePolicy(json: unknown): Result<string, IntakePolicy> {
|
||||
|
||||
## The sanctioned exception
|
||||
|
||||
Narrowing `unknown` to `Partial<Dto>` so you can *start* checking fields is fine — that's not a
|
||||
Narrowing `unknown` to `Partial<Dto>` so you can _start_ checking fields is fine — that's not a
|
||||
trust decision, it's just giving the compiler a shape to probe (`const dto = json as
|
||||
Partial<DashboardViewDto>`, see `dashboard-view.adapter.ts`). What's never fine is casting a
|
||||
field to its final domain type without having checked it first.
|
||||
|
||||
@@ -12,7 +12,11 @@ believe?). `src/app/shared/application/remote-data.ts` closes that off with one
|
||||
union instead:
|
||||
|
||||
```ts
|
||||
type RemoteData<E, T> = { tag: 'Loading' } | { tag: 'Empty' } | { tag: 'Failure'; error: E } | { tag: 'Success'; value: T };
|
||||
type RemoteData<E, T> =
|
||||
| { tag: 'Loading' }
|
||||
| { tag: 'Empty' }
|
||||
| { tag: 'Failure'; error: E }
|
||||
| { tag: 'Success'; value: T };
|
||||
```
|
||||
|
||||
## Combining sources
|
||||
@@ -50,7 +54,7 @@ flashes it; override with an `appAsyncLoading` template. `appAsyncEmpty` and
|
||||
This is a real Angular constraint, not an oversight: a structural directive's type
|
||||
parameter can only be inferred from an **input bound on that same element** (this is how
|
||||
`*ngFor="let x of items"` and `*ngIf="x as y"` work — the type comes from `ngForOf`/`ngIf`,
|
||||
inputs on the very same tag). `<ng-template appAsyncLoaded let-p>` sits on a *different*
|
||||
inputs on the very same tag). `<ng-template appAsyncLoaded let-p>` sits on a _different_
|
||||
node than `<app-async [data]="…">`, so `p` cannot inherit a type from that sibling input,
|
||||
even though they're nested in the same template. Angular types it `unknown`, and
|
||||
`ngTemplateContextGuard` can't fix that without an input to seed it from — the shared
|
||||
@@ -72,7 +76,7 @@ protected readonly loaded = computed(() => {
|
||||
```html
|
||||
<!-- in the template, inside <ng-template appAsyncLoaded> -->
|
||||
@if (loaded(); as s) {
|
||||
<app-letter-composer [brief]="s.brief" ... />
|
||||
<app-letter-composer [brief]="s.brief" ... />
|
||||
}
|
||||
```
|
||||
|
||||
@@ -93,5 +97,5 @@ fetch's loading/failure, which is a generic concern `RemoteData` already models.
|
||||
machine's own `loading`/`failed` tags purely mirror the fetch (nothing extra beyond "not
|
||||
loaded yet" / "the GET failed"), project them onto a `RemoteData` computed at the store
|
||||
layer for `<app-async>` to render, the way `BriefStore.remoteData` does — the machine
|
||||
keeps deciding what the *letter* is doing, `RemoteData` keeps deciding what the *fetch* is
|
||||
keeps deciding what the _letter_ is doing, `RemoteData` keeps deciding what the _fetch_ is
|
||||
doing.
|
||||
|
||||
Reference in New Issue
Block a user