From 4e9eeb99c4b417fdc8e09678795b7b33af0f462f Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sat, 16 May 2026 19:23:00 +0200 Subject: [PATCH] fix(lint): mode:'file' for the components-foundation Icon.vue bridge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Plan-1 Task-4 added { type:'components-foundation', pattern: 'src/components/Icon.vue' } without mode:'file'. eslint-plugin-boundaries defaults to folder mode, so the single-file pattern never matched and Icon.vue fell through to the generic `components` catch-all — breaking the sanctioned components-v2 -> Icon bridge (RFC AD-G5) for every v2 shell component. Plan-1's boundary test only exercised the forms/** folder-glob edge so the gap was latent. Adds mode:'file' + a regression test locking the components-v2 -> Icon.vue edge. Co-Authored-By: Claude Opus 4.7 --- apps/app/.eslintrc.cjs | 8 +++++++- apps/app/tests/unit/boundaries-v2.spec.ts | 12 ++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/app/.eslintrc.cjs b/apps/app/.eslintrc.cjs index 5d74d343..ee51fb29 100644 --- a/apps/app/.eslintrc.cjs +++ b/apps/app/.eslintrc.cjs @@ -306,7 +306,13 @@ module.exports = { // same `type` so both src/components/forms/** and src/components/Icon.vue // are captured before the generic `components` catch-all. { type: 'components-foundation', pattern: 'src/components/forms/**' }, - { type: 'components-foundation', pattern: 'src/components/Icon.vue' }, + // mode:'file' is REQUIRED for a single-file pattern. Without it + // eslint-plugin-boundaries matches in the default 'folder' mode, + // so 'src/components/Icon.vue' never matches and Icon.vue falls + // through to the generic `components` catch-all below — breaking + // the sanctioned components-v2 → Icon bridge (RFC AD-G5). The + // forms/** entry above is a folder glob so it is unaffected. + { type: 'components-foundation', pattern: 'src/components/Icon.vue', mode: 'file' }, { type: 'components-v2', pattern: 'src/components-v2/**' }, { type: 'components', pattern: 'src/components/**' }, { type: 'layouts', pattern: 'src/layouts/**' }, diff --git a/apps/app/tests/unit/boundaries-v2.spec.ts b/apps/app/tests/unit/boundaries-v2.spec.ts index e50ec52a..8b1b7be7 100644 --- a/apps/app/tests/unit/boundaries-v2.spec.ts +++ b/apps/app/tests/unit/boundaries-v2.spec.ts @@ -38,6 +38,18 @@ describe('boundaries — v2 zones', () => { expect(errs).toHaveLength(0) }) + it('allows components-v2 → components-foundation (Icon.vue bridge, single-file mode:file)', async () => { + // Regression lock: the single-file element needs mode:'file' or + // Icon.vue falls through to the generic `components` catch-all and + // every v2 shell component's Icon import breaks (RFC AD-G5 bridge). + const errs = await boundaryErrors( + 'src/components-v2/layout/SidebarNav.vue', + '', + ) + + expect(errs).toHaveLength(0) + }) + it('allows components-v2 → components-foundation (FormField bridge)', async () => { const errs = await boundaryErrors( 'src/components-v2/forms/Demo.vue',