chore(workspace): tsconfig composite refs + axe-linter false-positive config #147
Reference in New Issue
Block a user
Delete Branch "chore/tsconfig-composite-axe-linter"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Three editor-noise sources flagged by the VS Code TypeScript service + the Deque axe Linter extension, each tamed at the right layer. No runtime behaviour change.
libs/{shared/ui,shared/state,feature/auth}must havecomposite: true. Nx 22's lib generator doesn't emitcomposite; modern VS Code TS service flags it.composite: trueto each lib'stsconfig.lib.json, letnx syncredirect consumer references inapps/portal-{shell,admin}/tsconfig.app.jsonto point at the.lib.jsondirectly.moduleResolution: "node"/"node10"deprecated, removed in TS 7.0. Two hits on the BFF tsconfigs.ignoreDeprecations: "5.0"onapps/portal-bff/tsconfig.{app,spec}.json— the opt-out knob the diagnostic itself suggests. A proper migration tonodenext/node16is a separate chantier.<ul>"must only directly contain<li>,<script>, or<template>" — fires on Angular 17+@forblocks inside lists. Pure static-linter limitation; rendered DOM is fine..axe-linter.ymlat repo root:global-disable: [list].What lands
composite: trueon lib.lib.jsonlibs/shared/ui/tsconfig.lib.json,libs/shared/state/tsconfig.lib.json,libs/feature/auth/tsconfig.lib.jsongetcomposite: trueadded.nx syncthen automatically rewrites consumer references:in
apps/portal-shell/tsconfig.app.jsonandapps/portal-admin/tsconfig.app.json. Semantically cleaner — the app references the lib's actual compile config (which produces the.d.tsit consumes), not the lib's solution-style root tsconfig.Earlier attempt — composite on the solution
tsconfig.json— silently brokevitest: the Angular Vite plugin chokes on a composite project withfiles: []/include: []and falls through, leaving spec files loaded but tests not registered ("No test suite found in file"). Movingcompositeto.lib.json(the project that actually has inputs) fixes the contract without poking the plugin.ignoreDeprecations: "5.0"apps/portal-bff/tsconfig.app.jsonandapps/portal-bff/tsconfig.spec.json— silencesOption 'moduleResolution=node10' is deprecated and will stop functioning in TypeScript 7.0. The diagnostic suggests"6.0"as the value, but TS 5.9 (our pinned version) only accepts"5.0"; using"6.0"results inTS5103: Invalid value for '--ignoreDeprecations'and breaks every spec."5.0"is the current-gen accepted value.The deprecation is real — TS 7.0 will drop both
"node"and"node10"moduleResolutionmodes. The migration target ismoduleResolution: "nodenext"paired with matchingmodule: "nodenext", but that interacts non-trivially with Nest's CommonJS pipeline and the BFF's import semantics. Out of scope for a drive-by fix; we'll handle it as a dedicated chantier when TS 7.0 lands on the roadmap..axe-linter.ymlNew file at repo root:
The Deque axe Linter VS Code extension reads
.axe-linter.ymlat workspace root. Thelistrule (WCAG 1.3.1) fires false positives on Angular 17+ control-flow syntax —@for (item of list; ...) { <li>… }looks like a non-<li>child of<ul>to a static HTML scanner. The Angular compiler erases those tokens at build time; the rendered DOM is compliant. CI accessibility coverage is provided byaxe-playwrightper ADR-0016 §"Tooling" — it runs against the rendered DOM and is unaffected by this disable.Notes for the reviewer
composite: trueon every lib? Per CLAUDE.md "no premature abstractions" —libs/shared/{tokens,util}are not currently referenced by anytsconfig.app.json, so they don't trigger TS6306. Addingcompositeto them would be future-proofing without a current consumer. When a consumer reference is added, the same one-line fix lands then.moduleResolutionproperly? The BFF runs on Nest's CommonJS pipeline;nodenextbrings stricter ESM resolution (.jsextensions in imports, packageexportsmap enforcement) that ripples through. Not a 5-minute change. TheignoreDeprecationsknob is the textbook defer mechanism for exactly this case.listglobally rather than per-file? The rule's false-positive pattern (<ul><@for>/<ol><@for>) applies workspace-wide; we use@forconsistently acrossportal-shell+portal-admin. Per-file disables would multiply as new templates land. axe-playwright remains the authoritative check on the rule.Test plan
pnpm nx run-many -t lint test build --projects=portal-shell,portal-admin,portal-bff,shared-ui,shared-state,feature-auth— 18/18 tasks pass. 517 specs green across the affected projects.pnpm nx sync:check— workspace in sync after the changes; runningsyncagain is a no-op.tsconfig.jsonfiles should be gone, the twomoduleResolution=node10deprecation lines on BFF tsconfigs should be silenced, and thelistrule undersidebar.html(portal-admin) should no longer surface.Three editor-noise sources, three matching tame: * Add `composite: true` to lib tsconfig.lib.json files (shared/ui, shared/state, feature/auth) and let `nx sync` redirect consumer references in apps/portal-{shell,admin}/tsconfig.app.json to point at the .lib.json directly. Silences TS6306 ("Referenced project must have setting composite: true") that the TS service raises on the project references our Nx 22 lib generator emits. * Add `ignoreDeprecations: "5.0"` on apps/portal-bff/tsconfig.{app, spec}.json. Both inherit `moduleResolution: node` / `node10` which TS 7.0 will remove; the diagnostic itself suggests the opt-out knob. The TS 5.9 we run only accepts "5.0" as the value (the warning text mentions "6.0" but TS rejects it). Migration to nodenext/node16 is a separate chantier — too entangled with Nest CJS semantics for a drive-by. * Add a repo-level .axe-linter.yml that disables the `list` rule globally. axe Linter (VS Code) doesn't understand Angular 17+ `@for` blocks and flags `@for (...) { <li>… }` as a non-<li> child of <ul>/<ol>. Compiler erases the syntax at build time; axe-playwright (ADR-0016) operates on the rendered DOM and is unaffected.