fix(layer): type-check clean inside a strict Nuxt 4 consumer: relative imports, indexed access, and three real bugs (stacked on #72) #73

Open
A-Guevara wants to merge 1 commit from fix/consumer-strict-types into claude/reconcile-forgejo-github-89de62
Owner

Stacked on #72. Its base is #72's branch, so the diff here is this one commit. Once #72 merges, retarget this PR to main (Forgejo may do it automatically if #72's branch is deleted).

Why

A consumer that extends the layer type-checks the layer's source under its own tsconfig. Landscape vendors a 3.1.0 tarball built from 5babb1e. Under Nuxt 4 defaults (strict, noUncheckedIndexedAccess) it finds 145 errors in the layer's files, and its CI filters them out as a stopgap until a clean 3.1.1 is vendored. With this commit it finds none. This is the fix intended for 3.1.1.

What changes

  • ~/ imports become relative (17 imports in 11 files). In layer components and utils, ~/ resolves against the consumer's srcDir, so ~/composables/useTuxVisionPrefs, ~/utils/tuxEChartsTheme and ~/assets/geo/* pointed into the consumer. Demo pages keep ~/ because consumers never compile them.
  • @types/sanitize-html moves to dependencies. The layer's render.ts imports sanitize-html, and a consumer installs only dependencies.
  • Explicit guards on indexed access where the bounds already hold:
    • mdc-converter's line loop now uses a bounds-checked at(i);
    • regex groups get ?? "";
    • the series marker and dash cycles;
    • the sidebar's rail flyout now goes through a hoveredSection computed;
    • block swaps in the web builder.

Real bugs the types surfaced (runtime behaviour changes)

  • desk/render.ts: a disallowed <video> returned attribs: "span" (a string). It now becomes an empty <span>, as a disallowed <img> already does.
  • TuxDeskInspector: the column picker's mouseenter wrote .value onto an injected ref the template had already unwrapped, so the canvas grid highlight never updated. The write now happens in a script function.
  • Desk presets: badgeTone allowed "ok", which TuxBadge doesn't accept, so it rendered unstyled. The preset type now says "success". No preset used "ok". The command palette's own "ok" class tone is unchanged.

Type gaps only (no runtime change)

  • TuxChartDonut arcs carry patternKind, but the Arc type didn't declare it.
  • TuxReactiveSidebar's search-filter type predicate couldn't hold, so filteredSections kept | null in its type.

Provenance

This is commit 7e467c0 (built on 5babb1e, saved as a bundle in Landscape's .git/backups), rebased onto #72's merge. It applied without conflict, the diff content is identical, and app/, server/ and nuxt.config.ts are byte-identical to 7e467c0. So Landscape's 145 → 0 result carries over unchanged.

Checks (local, Node 26.0.0)

check #72 (7a1db31) this branch (379d1ac)
lockfile regenerated with npm@12.0.2 --package-lock-only no change no change
npm ci, npm 11.12.1 and 12.0.2 pass pass
npx eslint . 0 errors (262 warnings) 0 errors (260 warnings)
npx vue-tsc --noEmit 200 errors 80 errors, all already in the 200. All 80 are in app/pages/** and app/app.vue; none are in components, composables or utils.
npx vitest run 220 files, 699 tests 220 files, 699 tests pass
React workspace tests 26 files, 89 tests 26 files, 89 tests pass
trivy HIGH/CRITICAL, .security-ignore applied 0 0
gitleaks tree scan no leaks no leaks

After 3.1.1

Landscape re-vendors frontend/vendor/tti-tti-ux-3.1.1.tgz and drops the temporary vue-tsc filter in .forgejo/workflows/ci-frontend.yml. That's a separate change in the Landscape repo.

**Stacked on #72.** Its base is #72's branch, so the diff here is this one commit. Once #72 merges, retarget this PR to `main` (Forgejo may do it automatically if #72's branch is deleted). ## Why A consumer that `extends` the layer type-checks the layer's source under its own tsconfig. Landscape vendors a 3.1.0 tarball built from 5babb1e. Under Nuxt 4 defaults (`strict`, `noUncheckedIndexedAccess`) it finds 145 errors in the layer's files, and its CI filters them out as a stopgap until a clean 3.1.1 is vendored. With this commit it finds none. This is the fix intended for 3.1.1. ## What changes - **`~/` imports become relative (17 imports in 11 files).** In layer components and utils, `~/` resolves against the *consumer's* srcDir, so `~/composables/useTuxVisionPrefs`, `~/utils/tuxEChartsTheme` and `~/assets/geo/*` pointed into the consumer. Demo pages keep `~/` because consumers never compile them. - **`@types/sanitize-html` moves to `dependencies`.** The layer's `render.ts` imports `sanitize-html`, and a consumer installs only dependencies. - **Explicit guards on indexed access where the bounds already hold:** - mdc-converter's line loop now uses a bounds-checked `at(i)`; - regex groups get `?? ""`; - the series marker and dash cycles; - the sidebar's rail flyout now goes through a `hoveredSection` computed; - block swaps in the web builder. ### Real bugs the types surfaced (runtime behaviour changes) - **`desk/render.ts`**: a disallowed `<video>` returned `attribs: "span"` (a string). It now becomes an empty `<span>`, as a disallowed `<img>` already does. - **`TuxDeskInspector`**: the column picker's `mouseenter` wrote `.value` onto an injected ref the template had already unwrapped, so the canvas grid highlight never updated. The write now happens in a script function. - **Desk presets**: `badgeTone` allowed `"ok"`, which `TuxBadge` doesn't accept, so it rendered unstyled. The preset type now says `"success"`. No preset used `"ok"`. The command palette's own `"ok"` class tone is unchanged. ### Type gaps only (no runtime change) - `TuxChartDonut` arcs carry `patternKind`, but the `Arc` type didn't declare it. - `TuxReactiveSidebar`'s search-filter type predicate couldn't hold, so `filteredSections` kept `| null` in its type. ## Provenance This is commit 7e467c0 (built on 5babb1e, saved as a bundle in Landscape's `.git/backups`), rebased onto #72's merge. It applied without conflict, the diff content is identical, and `app/`, `server/` and `nuxt.config.ts` are byte-identical to 7e467c0. So Landscape's 145 → 0 result carries over unchanged. ## Checks (local, Node 26.0.0) | check | #72 (7a1db31) | this branch (379d1ac) | |---|---|---| | lockfile regenerated with npm@12.0.2 `--package-lock-only` | no change | no change | | `npm ci`, npm 11.12.1 and 12.0.2 | pass | pass | | `npx eslint .` | 0 errors (262 warnings) | 0 errors (260 warnings) | | `npx vue-tsc --noEmit` | 200 errors | **80 errors, all already in the 200**. All 80 are in `app/pages/**` and `app/app.vue`; none are in components, composables or utils. | | `npx vitest run` | 220 files, 699 tests | 220 files, 699 tests pass | | React workspace tests | 26 files, 89 tests | 26 files, 89 tests pass | | trivy HIGH/CRITICAL, `.security-ignore` applied | 0 | 0 | | gitleaks tree scan | no leaks | no leaks | ## After 3.1.1 Landscape re-vendors `frontend/vendor/tti-tti-ux-3.1.1.tgz` and drops the temporary vue-tsc filter in `.forgejo/workflows/ci-frontend.yml`. That's a separate change in the Landscape repo.
fix(layer): type-check clean inside a strict Nuxt 4 consumer — relative imports, indexed access, and three real bugs
All checks were successful
baseline-security / baseline (push) Successful in 3m17s
ai-review / review (pull_request) Successful in 1m46s
baseline-security / baseline (pull_request) Successful in 2m37s
379d1acf76
A consumer that `extends` the layer type-checks its source under its own
tsconfig. Landscape (Nuxt 4 defaults: strict, noUncheckedIndexedAccess)
found 145 errors in 3.1.0's files; with this change it finds none.

- `~/` imports in layer components/utils resolve against the CONSUMER's
  srcDir, so `~/composables/useTuxVisionPrefs`, `~/utils/tuxEChartsTheme`
  and `~/assets/geo/*` pointed into the consumer: 17 imports in 11 files
  are now relative. (Demo pages keep `~/`: consumers never compile them.)
- `@types/sanitize-html` moves to dependencies: the layer's render.ts
  imports sanitize-html, and a consumer only installs dependencies.
- Indexed access made explicit where bounds already hold (mdc-converter's
  line loop via a bounds-checked `at(i)`, regex groups `?? ""`, the
  series marker/dash cycles, the sidebar's rail flyout via a
  `hoveredSection` computed, block swaps in the web builder).

Real bugs the types surfaced (runtime behaviour changes):
- desk/render.ts: a disallowed <video> returned `attribs: "span"` (a
  string); it now becomes an empty <span>, as a disallowed <img> does.
- TuxDeskInspector: the column picker's mouseenter wrote `.value` onto an
  injected ref the template had already unwrapped, so the canvas grid
  highlight never updated; the write moves into a script function.
- desk presets: badgeTone allowed "ok", which TuxBadge does not accept
  (rendered unstyled); the preset type now says "success". No preset
  used "ok". (The command palette's own "ok" class tone is unchanged.)

Type gaps only: TuxChartDonut arcs carry `patternKind` but the Arc type
did not say so; TuxReactiveSidebar's search-filter type predicate could
not hold, so filteredSections kept `| null` in its type.

tti-ux's own vue-tsc: 200 → 80 errors (the rest are pre-existing, mostly
demo pages); eslint clean; vitest 220 files / 699 tests pass.

AI review · advisory

The AI panel couldn't review this change right now (it will review the next push). Details for admins: panel HTTP 401: {"error": {"message": "missing Forgejo credential", "type": "auth", "code": 401}}

### AI review · advisory _The AI panel couldn't review this change right now (it will review the next push). Details for admins: panel HTTP 401: {"error": {"message": "missing Forgejo credential", "type": "auth", "code": 401}}_
All checks were successful
baseline-security / baseline (push) Successful in 3m17s
ai-review / review (pull_request) Successful in 1m46s
baseline-security / baseline (pull_request) Successful in 2m37s
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin "fix/consumer-strict-types:fix/consumer-strict-types"
git switch "fix/consumer-strict-types"

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch "claude/reconcile-forgejo-github-89de62"
git merge --no-ff "fix/consumer-strict-types"
git switch "fix/consumer-strict-types"
git rebase "claude/reconcile-forgejo-github-89de62"
git switch "claude/reconcile-forgejo-github-89de62"
git merge --ff-only "fix/consumer-strict-types"
git switch "fix/consumer-strict-types"
git rebase "claude/reconcile-forgejo-github-89de62"
git switch "claude/reconcile-forgejo-github-89de62"
git merge --no-ff "fix/consumer-strict-types"
git switch "claude/reconcile-forgejo-github-89de62"
git merge --squash "fix/consumer-strict-types"
git switch "claude/reconcile-forgejo-github-89de62"
git merge --ff-only "fix/consumer-strict-types"
git switch "claude/reconcile-forgejo-github-89de62"
git merge "fix/consumer-strict-types"
git push origin "claude/reconcile-forgejo-github-89de62"
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
tti/tti-ux!73
No description provided.