Parent
#576
What to build
Fix the last remaining RxJS 5 "unbound operator" call sites in the library, and add a lint rule so the pattern cannot come back.
Two sites remain in the sidenav container (patterns/layout/components/sidenav/sidenav.ts), both of the form first.call(this._ngZone.onMicrotaskEmpty).subscribe(...). Under RxJS 7 (this repo declares rxjs >=7.5.0) an operator imported from rxjs/operators is a factory that returns an OperatorFunction — calling it with .call(observable) returns a function, not an Observable, so the chained .subscribe(...) throws TypeError: ...subscribe is not a function at runtime. Convert both to observable.pipe(first()).
These are the same defect class already fixed in #655 (ScrollDispatcher.scrolled()) and #660 (tab-header.ts, tab-group.ts). A full sweep of src/ confirms these two are the only ones left; there are no legacy rxjs/add/* or rxjs/operator/* patch imports anywhere in the library.
Unlike the earlier three, these sites are not dead code. They sit inside subscribe callbacks on _sidenavs.changes and sidenav.onAlignChanged, so they throw whenever a sidenav is added or removed dynamically, or when a drawer's align changes at runtime. Static sidenav usage never reaches them, which is why #660 covered this file to ~85% without tripping either one.
Pair the fix with an ESLint no-restricted-syntax rule banning member calls of the form <rxjsOperator>.call(...). Keeping the rule in the same change as the last violation means a green CI run is itself the proof that no sites remain — and because the repo will have zero violations, eslint-baseline.json should not need to move.
Acceptance criteria
Blocked by
Parent
#576
What to build
Fix the last remaining RxJS 5 "unbound operator" call sites in the library, and add a lint rule so the pattern cannot come back.
Two sites remain in the sidenav container (
patterns/layout/components/sidenav/sidenav.ts), both of the formfirst.call(this._ngZone.onMicrotaskEmpty).subscribe(...). Under RxJS 7 (this repo declaresrxjs >=7.5.0) an operator imported fromrxjs/operatorsis a factory that returns anOperatorFunction— calling it with.call(observable)returns a function, not anObservable, so the chained.subscribe(...)throwsTypeError: ...subscribe is not a functionat runtime. Convert both toobservable.pipe(first()).These are the same defect class already fixed in #655 (
ScrollDispatcher.scrolled()) and #660 (tab-header.ts,tab-group.ts). A full sweep ofsrc/confirms these two are the only ones left; there are no legacyrxjs/add/*orrxjs/operator/*patch imports anywhere in the library.Unlike the earlier three, these sites are not dead code. They sit inside subscribe callbacks on
_sidenavs.changesandsidenav.onAlignChanged, so they throw whenever a sidenav is added or removed dynamically, or when a drawer'salignchanges at runtime. Static sidenav usage never reaches them, which is why #660 covered this file to ~85% without tripping either one.Pair the fix with an ESLint
no-restricted-syntaxrule banning member calls of the form<rxjsOperator>.call(...). Keeping the rule in the same change as the last violation means a green CI run is itself the proof that no sites remain — and because the repo will have zero violations,eslint-baseline.jsonshould not need to move.Acceptance criteria
first.call(this._ngZone.onMicrotaskEmpty)sites in the sidenav container use.pipe(first())and return anObservable_sidenavs.changesemits, and analignchange soonAlignChangedemits — each asserting the subscribe callback runs without throwing (transitions enabled; drawers re-validated)npm run lintpasses with no new entries ineslint-baseline.json(count unchanged or lower)npm run coverage:checkpasses;coverage-floor.jsonis not modified (see AGENTS.md — floor bumps land via Lock coverage-floor gate at 90% QASP target (epic top-off) #637)npm run format:checkand thetest-appbuild passBlocked by
sidenav.spec.ts; landing this first would conflict with it