WS-3 session 1b-ii Task 5b+c (audit Bucket E.2-E.5 — 6 items resolved,
2 promise/no-promise-in-callback warnings remain on dynamic-import
sites — see deviations).
This commit is split out from the originally-planned grouped Task 5
because the API stream timed out mid-session. E.1 (isAxiosError) is in
the preceding commit 0f155d9.
E.2 — vitest spec to Composition API (1× vue/component-api-style):
- useFormFailures.spec.ts: rewrote the test wrapper from
\`{ setup() { return { result } }, render: () => h('div') }\`
to \`setup(_, { expose }) { expose({ result }); return () => h('div') }\`.
Pure Composition API: setup returns the render function; expose()
declares the instance-visible \`result\` that the 7 \`vm.result.*\`
assertions consume. Tests still pass green (49 tests).
E.3 — REAL BUG: missing return in computed (1× vue/return-in-computed-property):
- useTimeSlotDropdown.ts:80: the \`fetchParams\` computed had a switch
over the \`DropdownScenario\` type (4 string-literal cases) without
a \`default\` branch. If \`scenario.value\` ever returned a value
outside the four narrowed cases (e.g. via a future type-assertion
drift), the computed silently returned \`undefined\`, and the
consumer code (\`fetchParams.value.includeParent\`) would throw
\`Cannot read property 'includeParent' of undefined\`. Added a
\`default\` branch returning \`{ includeParent: false, includeChildren: false }\`
— same as the 'flat' case (the safest baseline: include only own
slots, no hierarchy).
E.4 — SECURITY (1× vue/no-template-target-blank):
- pages/organisation/index.vue:343: the external website anchor had
\`target='_blank'\` with \`rel='noopener'\` (only one). The rule
requires the full \`rel='noopener noreferrer'\` pair. Updated.
Mitigates reverse-tabnabbing (window.opener) AND referrer-leakage
to the linked third-party site.
E.5 — axios fire-and-forget (3× promise/no-promise-in-callback,
1 fully resolved + 2 warnings remain):
- lib/axios.ts:42: changed \`error => Promise.reject(error)\` to
\`async error => { throw error }\`. Semantically identical (axios
interceptor onRejected returns a rejected promise either way) and
satisfies the lint rule.
- lib/axios.ts:61, 73: prefixed the dynamic-import chains with \`void\`
per Q4's option-a decision (\`void import('@/stores/...').then(...)\`).
This makes the discard intent explicit, but empirically does NOT
satisfy promise/no-promise-in-callback — the rule fires on any
promise creation inside a callback, regardless of the discard
pattern. The 2 warnings remain in the post-Task-5 baseline.
Resolution path is Bert's call: either keep \`void\` and accept
the warnings as documentation, or rewrite to \`async error => {
const { useStore } = await import(...); ... }\` which sequentializes
the dynamic-import resolution with the rejection. Out of scope for
this session per the literal Q4 recipe.
Tests + typecheck verified green.
Lint baseline: 34 → 32.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>