import { relative, sep } from 'node:path' import fsd from '@feature-sliced/steiger-plugin' import { defineConfig } from 'steiger' // Steiger is the official FSD linter: `bun run lint:fsd`. // 细粒度拆分是有意的架构决策:以下 feature 切片职责边界互斥、各自稳定, // 当前仅被 pages/workspace 消费,insignificant-slice 会对它们误报。 // 豁免采用「包装规则 + 过滤诊断」而非 files-scoped off —— 后者会把切片 // 从规则的分析输入中整体移除,导致 entities 的消费边丢失而产生连锁误报。 // 这里保留完整引用分析,只对清单内的切片丢弃报警:规则对新切片仍然生效。 // 本清单应随架构演进同步修剪(切片被第二个消费者使用,或删除后记得移除)。 const INSIGNIFICANT_SLICE_ALLOWLIST = new Set([ 'entities/search', 'features/chat', 'features/issue-board', 'features/notifications', 'features/pull-request', 'features/repo-branches', 'features/repo-browse', 'features/repo-history', 'features/repo-settings', 'features/repo-releases', 'features/search', 'features/space-discovery', 'features/space-management', 'features/user-settings', ]) // 插件内部用 path.join() 拼路径:Windows 下 relative() 产出 `features\\chat`,/ 分隔的清单会静默失效。 // 统一归一化为 POSIX 分隔符再比对,保证跨平台行为一致。 const toPosixPath = (value) => value.split(sep).join('/') const GUARDED_RULE_NAME = 'project/insignificant-slice' const officialSliceRule = fsd.plugin.ruleDefinitions.find(({ name }) => name === 'fsd/insignificant-slice') const guardedPlugin = { ...fsd.plugin, meta: { name: 'fsd-with-allowlist', version: fsd.plugin.meta.version }, ruleDefinitions: fsd.plugin.ruleDefinitions.map((rule) => rule === officialSliceRule ? { name: GUARDED_RULE_NAME, async check(root, options) { const { diagnostics } = await officialSliceRule.check(root, options) return { diagnostics: diagnostics.filter( ({ location }) => !INSIGNIFICANT_SLICE_ALLOWLIST.has(toPosixPath(relative(root.path, location.path))), ), } }, } : rule, ), } const renameGuardedRule = (configEntry) => configEntry.rules?.['fsd/insignificant-slice'] === undefined ? configEntry : (() => { const { ['fsd/insignificant-slice']: severity, ...restRules } = configEntry.rules return { ...configEntry, rules: { ...restRules, [GUARDED_RULE_NAME]: severity } } })() export default defineConfig([ guardedPlugin, // recommended 首项携带原始 plugin,换成 guardedPlugin 后需剔除,避免同名规则冲突。 ...fsd.configs.recommended.filter((entry) => !('ruleDefinitions' in entry)).map(renameGuardedRule), { ignores: [ '**/node_modules/**', '**/dist/**', 'src/shared/api/**', // auto-generated by `bun run gen:api` 'src/shared/livekit/**', // vendored @livekit/components-react|core|styles ], }, ])