69f12aa
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-pipelines',
'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
],
},
])