@jayyuen66/dsh-plugin-shared 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{createRequire as e}from"node:module";import{defineConfig as t}from"oxlint";function n(e){return(typeof e==`string`?e:`${e.name} ${e.specifier}`).includes(`sonarjs`)}const r=`同 no-unsafe-member-access`,i={"vitest/*":{kind:`文体作用域`,measured:7,note:`用例结构类判据在非用例文件上无从计算`},"vitest/no-hooks":{kind:`上游不推荐`,measured:181,note:`禁用 hook 本身;本仓按官方 vitest 用法大量使用 before*/after*`},"vitest/no-conditional-in-test":{kind:`文体作用域`,measured:523,note:`平台/宿主版本分支是刻意的(macOS 与 Linux 的家目录形状、0.1.7 与 0.1.6 的 API 面)`},"vitest/max-expects":{kind:`上游不推荐`,measured:163,note:`给单条用例的断言条数设上限属口味,不指向缺陷`},"vitest/prefer-expect-assertions":{kind:`上游不推荐`,measured:2902,note:`要求每个 async 用例手写 expect.assertions(n),是与断言强度无关的计数仪式`},"vitest/require-test-timeout":{kind:`上游不推荐`,measured:2892,note:`要求每条用例显式 timeout;本仓用泵式假时钟,超时由 13 份 vitest 配置统一给`},"vitest/prefer-importing-vitest-globals":{kind:`实测否证`,measured:0,note:`autofix 方向是删掉显式 import 改回裸全局;13 份 vitest 配置都没开 globals:true,应用后当场 3605 处 TS2593、测试全废`},"vitest/no-importing-vitest-globals":{kind:`实测否证`,measured:133,note:`与上一条同族、方向相反,两条同时开就是把两种写法都判死`},"vitest/prefer-import-in-mock":{kind:`实测否证`,measured:6,note:"动态形态按完整模块面校验工厂返回值,而 @types/node 的 os、@types/react 都是 `export =` 形状、类型面上没有 default;实测三处 TS2769+TS2740/2741,react 那处无论怎么 spread 都补不出 default"},"vitest/prefer-lowercase-title":{kind:`文体作用域`,measured:171,note:`只在用例文件里生效:它带 autofix,实测一轮 oxlint --fix 静默小写化了 260 条标题(含 nO_VERIFY 这种坏名)。包级 titlePrefixes 只留真正的技术名(GET/CSRF/组件名…):非技术名(工单号一类)不该借这条豁免留在标题里,而中文开头的标题天然满足判据(无大小写)⇒ 免检面能收多小收多小。实测 oxlint 前缀一命中就把整条标题免检,所以陈旧条目由配置基线自检按『免检面未被使用』点名,不靠人工巡检`},"vitest/prefer-called-times":{kind:`对侧互斥`,measured:0,note:`探针实测(同文件四种写法各跑一次):toHaveBeenCalledTimes(1) 被 prefer-called-once 判死、toHaveBeenCalledOnce() 被本条判死、expect(spy.mock.calls).toHaveLength(1) 被 prefer-to-have-been-called-times 判死,只有 n>=2 能同时满足三条 ⇒ 三条同开等于「单次调用」这条断言无法书写(实测逼得消费方改用 assert.equal(spy.mock.calls.length, 1) 绕行)。留 prefer-called-once 与 prefer-to-have-been-called-times 两条方向一致的组合,关本条`},"vitest/prefer-describe-function-title":{kind:`对侧互斥`,measured:48,note:"要求 `describe(fn)`,而 valid-title 要求字符串字面量(oxlint 1.85 的 valid-title 是 DummyRule、无任何选项);上游 recommended 收的是 valid-title,取它,26 处 `describe(fn)` 按代码改成同名字符串"},"vitest/prefer-to-be-truthy":{kind:`实测否证`,measured:117,note:`把 toStrictEqual(true) 放宽成 toTruthy(),接受任意真值是削弱断言`},"vitest/prefer-to-be-falsy":{kind:`实测否证`,measured:89,note:`同族,放宽成 toFalsy() 同样是削弱断言`},"import/no-default-export":{kind:`契约冲突`,measured:38,note:`官方 cordis 入口就是 default export(vendor/loader/src/index.ts 的 unwrapExports 先 unwrap default),12 条正是 12 个 bundle 入口`},"import/no-named-export":{kind:`契约冲突`,measured:895,note:`13 个包与上游 deepseek-harness 一样以具名导出 + 子路径说明符对外暴露`},"import/prefer-default-export":{kind:`契约冲突`,measured:58,note:`与 no-default-export 同族、方向与 cordis 入口相反`},"import/no-nodejs-modules":{kind:`契约冲突`,measured:448,note:"host 半就跑在 node 上,`node:` 内置模块是运行环境本身而不是越界"},"import/no-named-as-default-member":{kind:`契约冲突`,measured:47,note:`对具名导出的默认对象做成员访问是本仓消费官方声明的常态`},"import/no-anonymous-default-export":{kind:`契约冲突`,measured:12,note:`官方 cordis 入口是匿名对象 default export(registry.ts 的 RegistryService.plugin() 读 name/Config,isApplicable() 判 apply),具名化等于改官方形态`},"eslint/no-duplicate-imports":{kind:`实测否证`,measured:166,note:`ESLint 官方已废弃(不区分 import type),由 import/no-duplicates 取代`},"import/group-exports":{kind:`上游不推荐`,measured:766,note:`要求单点导出,与具名导出面冲突`},"import/exports-last":{kind:`上游不推荐`,measured:528,note:`要求导出语句在文件末尾`},"import/no-relative-parent-imports":{kind:`上游不推荐`,measured:277,note:`包内 lib/ 与 test/ 的相对父级引用是既有结构`},"import/max-dependencies":{kind:`上游不推荐`,measured:25,note:`给 import 条数设上限;host 半消费官方服务面天然依赖多`},"node/no-process-env":{kind:`上游不推荐`,measured:51,note:`环境变量是本仓的输入面(DSH_HOME、profile 目录、构建期开关);eslint-plugin-n 的 recommended 也不含本条`},"eslint/no-magic-numbers":{kind:`上游不推荐`,measured:5774,note:`把 HTTP 状态码/毫秒阈值抽成常量的计数规则`},"eslint/sort-keys":{kind:`上游不推荐`,measured:4101,note:`对象键排序;成对字面量与 locale 字典的可读性会一起牺牲`},"eslint/sort-imports":{kind:`上游不推荐`,measured:675,note:`字母序 import,与 oxfmt 的分组形态冲突`},"eslint/capitalized-comments":{kind:`上游不推荐`,measured:2388,note:`本仓注释以中文为主,「首字母大写」对中文注释无从判定`},"eslint/no-ternary":{kind:`上游不推荐`,measured:1024,note:`禁三元;改写成 if/else 并不会更正确`},"eslint/no-undefined":{kind:`上游不推荐`,measured:2009,note:"禁 `undefined` 字面量,与本仓大量显式可选返回形态冲突"},"eslint/no-void":{kind:`上游不推荐`,measured:172,note:"禁 `void` 前缀,而 `void promise` 正是消解 no-floating-promises 的官方写法"},"unicorn/no-null":{kind:`上游不推荐`,measured:788,note:`禁 null;官方声明与 JSON 边界大量用 null,改成 undefined 会改变序列化形状`},"typescript/prefer-readonly-parameter-types":{kind:`上游不推荐`,measured:2433,note:`要求每个入参类型全 readonly;官方声明面(SessionEvent/ConfigForm 等)是可变的,改不动也不该改`},"oxc/no-async-await":{kind:`对侧互斥`,measured:2160,note:`禁 async/await,而同表里 promise-function-async、require-await、no-floating-promises 都在推 async`},"oxc/no-optional-chaining":{kind:`对侧互斥`,measured:1354,note:"禁 `?.`,而 typescript/prefer-optional-chain 正在要求把 && 链改成 `?.`"},"oxc/no-rest-spread-properties":{kind:`对侧互斥`,measured:550,note:`禁对象 spread,而 ES2024 目标与官方声明的投影写法都靠它`},"typescript/no-explicit-any":{kind:`文体作用域`,measured:1,note:`用例里的桩件面(mini-react 之类)需要 any 才塞得进官方签名`},"typescript/no-non-null-assertion":{kind:`文体作用域`,measured:536,note:"用例里 `!` 是「前驱条件已成立」的最短写法"},"typescript/no-unsafe-type-assertion":{kind:`文体作用域`,measured:844,note:"桩件需要 `as never` / `as unknown as` 跨官方名义类型"},"typescript/require-await":{kind:`文体作用域`,measured:467,note:`官方 async 契约的同步实现与测试替身撑不住这条;prod 侧的条数按代码修,不进豁免`},"eslint/require-await":{kind:`对侧互斥`,measured:481,note:`它与 typescript/require-await 是同一条判据的两份实现,不是两条判据:探针实测(一段无 await 的 async 函数、--type-aware)单开各自都报、同开报两次 ⇒ 2 errors / 1 defect。按 typescript-eslint 官方的 extension-rule 口径裁决:留带类型信息的扩展那条、关基线那条。覆盖面没有因此变小:全仓逐行去重实测 514 行两点同报、typescript 独有 0 行、eslint 独有只落在用例面与配置自身的中间态;而 --type-aware 实测对 .mjs 也会由扩展那条报出,所以 scripts/*.mjs 面不需要基线那条补位。用例文件由 TEST_OVERRIDES 整族豁免`},"eslint/max-statements":{kind:`文体作用域`,measured:549,note:`用例体天然长(given/when/then 展开)`},"eslint/max-lines-per-function":{kind:`文体作用域`,measured:365,note:`同上`},"eslint/max-lines":{kind:`文体作用域`,measured:54,note:`单个用例文件的长度不作为缺陷信号`},"node/no-sync":{kind:`文体作用域`,measured:299,note:`构建脚本与门禁脚本按设计同步读;生产代码的写侧由每包 syncWrites 逐项登记,不在豁免里`},"node/no-top-level-await":{kind:`文体作用域`,measured:53,note:`脚本以 node 直接执行,顶层 await 是 ESM 常态;prod 侧 0 条`},"typescript/strict-boolean-expressions":{kind:`文体作用域`,measured:0,note:`scripts/*.mjs 无类型面,隐式 any 上无从判定`},"typescript/no-implied-eval":{kind:`文体作用域`,measured:0,note:`同上:这条要类型信息才能判`},"typescript/no-unsafe-member-access":{kind:`文体作用域`,measured:0,note:`无类型标注的脚本里每个值都落进隐式 any`},"typescript/no-unsafe-call":{kind:`文体作用域`,measured:0,note:r},"typescript/no-unsafe-assignment":{kind:`文体作用域`,measured:0,note:r},"typescript/no-unsafe-return":{kind:`文体作用域`,measured:0,note:r},"typescript/no-unsafe-argument":{kind:`文体作用域`,measured:0,note:r},"typescript/require-array-sort-compare":{kind:`文体作用域`,measured:0,note:`无类型脚本里「比较器缺失」判不出来`},"unicorn/no-process-exit":{kind:`文体作用域`,measured:2,note:`CLI 脚本的 process.exit 就是它的返回方式`},"eslint/no-continue":{kind:`文体作用域`,measured:53,note:`只对 scripts/ 豁免:TS 侧实测 0 条(包代码本来就不用 continue),908 行的门禁脚本改成嵌套 if 只会更难读`},"unicorn/max-nested-calls":{kind:`文体作用域`,measured:59,note:`只对 scripts/ 豁免:TS 侧实测 0 条;CLI 脚本里链式 map/filter/join 的深度由数据形状决定,不指向缺陷`},"unicorn/no-useless-undefined":{kind:`文体作用域`,measured:0,note:`脚本侧同上调;prod 仍按配置项 checkArguments:false 生效`},"react/set-state-in-effect":{kind:`契约冲突`,measured:16,note:`卡片用 effect 同步宿主态到 store 是挂载适配器形态;Compiler 建议的 render 期推导要改写 12 份适配器的状态流`},"react/no-deriving-state-in-effects":{kind:`契约冲突`,measured:7,note:`适配器形态里「props/state 派生值在 effect 对齐宿主」是挂载动作,不是可下沉到 render 的纯派生`},"react/exhaustive-effect-dependencies":{kind:`契约冲突`,measured:8,note:`Compiler 版依赖审计对适配器的内联闭包全量追问;与 react-hooks/exhaustive-deps(保留并已修)形成双门,留后者`},"react/hooks":{kind:`契约冲突`,measured:13,note:`「同一 hook 函数跨渲染同引用」在适配器的内联闭包形态下整体不成立;收敛批次把闭包提升后再回来开`},"react/refs":{kind:`契约冲突`,measured:1,note:`挂载适配器在 render 期读 ref 对齐宿主布局;收敛批次改成挂载后读`},"react/todo":{kind:`上游不推荐`,measured:6,note:`报的是 React 编译器 BuildHIR 自己不支持 try/catch(-finally) 的上游 TODO,不是代码缺陷`},"react/rules-of-hooks":{kind:`文体作用域`,measured:3,note:`只对用例文件豁免(TEST_FILE_OVERRIDES):测试架在组件树外直接驱动卡片适配 hook(useCardOf / useSyncExternalStore 桩),调用次数顺序由桩件固定。键用表载前缀 react/(诊断文案显示 react-hooks(...) 是显示名,配置键以 --rules 的 Source 列为准)`}},a=[`typescript/no-empty-object-type`],o=[`existsSync`,`readFileSync`,`readdirSync`,`readSync`,`realpathSync`,`statSync`],s=[`eslint`,`typescript`,`unicorn`,`oxc`,`node`,`promise`,`vitest`,`import`,`react`,`jsx-a11y`],c=[`eslint-plugin-sonarjs`,`eslint-plugin-sonarjs/cjs/plugin.js`];function l(){let t=e(import.meta.url),n=[];for(let e of c)try{return t.resolve(e)}catch{n.push(e)}throw Error(`oxlint 基线要挂 eslint-plugin-sonarjs,但从本包解析不到它(试过 ${n.join(`、`)})。要么在本包 devDependencies 里装 eslint-plugin-sonarjs,要么把你自己解析到的 sonarjs 入口经 definePluginConfig({ jsPlugins: [...] }) 传进来(入口路径须指向 sonarjs:SONARJS_RULES 无条件引用它,别家的插件救不了这一条)。`)}function u(e,t=l){let r=e??[],i=null;try{i=t()}catch(e){if(!r.some(e=>n(e)))throw e}return i===null?[...r]:[i,...r.filter(e=>e!==i)]}const d={"sonarjs/no-identical-functions":`error`,"sonarjs/no-duplicated-branches":`error`,"sonarjs/no-all-duplicated-branches":`error`,"sonarjs/no-collapsible-if":`error`,"sonarjs/no-identical-conditions":`error`,"sonarjs/no-identical-expressions":`error`,"sonarjs/no-duplicate-string":`error`,"sonarjs/cognitive-complexity":`error`,"sonarjs/max-switch-cases":`error`,"sonarjs/no-inverted-boolean-check":`error`,"sonarjs/no-duplicate-in-composite":`error`,"sonarjs/duplicates-in-character-class":`error`,"sonarjs/no-useless-catch":`error`,"sonarjs/no-extra-arguments":`error`,"sonarjs/no-redundant-assignments":`error`,"sonarjs/prefer-single-boolean-return":`error`,"sonarjs/label-position":`error`},f={correctness:`error`,suspicious:`error`,style:`error`,perf:`error`,restriction:`error`,pedantic:`error`,nursery:`error`},p={typeAware:!0,typeCheck:!0,denyWarnings:!0,maxWarnings:0,reportUnusedDisableDirectives:`error`,respectEslintDisableDirectives:!1},m=[`**/node_modules/**`,`.toolchain/**`,`coverage/**`,`dist/**`,`client.js`,`host.js`],h=/* @__PURE__ */ `vitest/consistent-each-for.vitest/consistent-test-filename.vitest/consistent-test-it.vitest/consistent-vitest-vi.vitest/expect-expect.vitest/hoisted-apis-on-top.vitest/max-expects.vitest/max-nested-describe.vitest/no-alias-methods.vitest/no-commented-out-tests.vitest/no-conditional-expect.vitest/no-conditional-in-test.vitest/no-conditional-tests.vitest/no-disabled-tests.vitest/no-duplicate-hooks.vitest/no-focused-tests.vitest/no-hooks.vitest/no-identical-title.vitest/no-import-node-test.vitest/no-importing-vitest-globals.vitest/no-interpolation-in-snapshots.vitest/no-large-snapshots.vitest/no-mocks-import.vitest/no-restricted-matchers.vitest/no-restricted-vi-methods.vitest/no-standalone-expect.vitest/no-test-prefixes.vitest/no-test-return-statement.vitest/no-unneeded-async-expect-function.vitest/padding-around-after-all-blocks.vitest/padding-around-test-blocks.vitest/prefer-called-exactly-once-with.vitest/prefer-called-once.vitest/prefer-called-times.vitest/prefer-called-with.vitest/prefer-comparison-matcher.vitest/prefer-describe-function-title.vitest/prefer-each.vitest/prefer-equality-matcher.vitest/prefer-expect-assertions.vitest/prefer-expect-resolves.vitest/prefer-expect-type-of.vitest/prefer-hooks-in-order.vitest/prefer-hooks-on-top.vitest/prefer-import-in-mock.vitest/prefer-importing-vitest-globals.vitest/prefer-lowercase-title.vitest/prefer-mock-promise-shorthand.vitest/prefer-mock-return-shorthand.vitest/prefer-snapshot-hint.vitest/prefer-spy-on.vitest/prefer-strict-boolean-matchers.vitest/prefer-strict-equal.vitest/prefer-to-be.vitest/prefer-to-be-falsy.vitest/prefer-to-be-object.vitest/prefer-to-be-truthy.vitest/prefer-to-contain.vitest/prefer-to-have-been-called-times.vitest/prefer-to-have-length.vitest/prefer-todo.vitest/require-awaited-expect-poll.vitest/require-hook.vitest/require-local-test-context-for-concurrent-snapshots.vitest/require-mock-type-parameters.vitest/require-test-timeout.vitest/require-to-throw-message.vitest/require-top-level-describe.vitest/valid-describe-callback.vitest/valid-expect.vitest/valid-expect-in-promise.vitest/valid-title.vitest/warn-todo`.split(`.`),g=/* @__PURE__ */ new Set([`vitest/max-expects`,`vitest/no-conditional-in-test`,`vitest/no-hooks`,`vitest/no-importing-vitest-globals`,`vitest/prefer-called-times`,`vitest/prefer-describe-function-title`,`vitest/prefer-expect-assertions`,`vitest/prefer-import-in-mock`,`vitest/prefer-importing-vitest-globals`,`vitest/prefer-to-be-falsy`,`vitest/prefer-to-be-truthy`,`vitest/require-test-timeout`]),_={"eslint/one-var":[`error`,`never`],"eslint/func-style":[`error`,`declaration`,{allowArrowFunctions:!0,overrides:{namedExports:`ignore`}}],"eslint/id-length":[`error`,{exceptions:[`a`,`i`,`t`,`x`,`y`,`z`]}],"eslint/init-declarations":[`error`,`never`,{ignoreForLoopInit:!0}],"eslint/max-lines":[`error`,{max:2e3,skipBlankLines:!0,skipComments:!0}],"eslint/max-lines-per-function":[`error`,{max:120,skipBlankLines:!0,skipComments:!0}],"eslint/complexity":`error`,"eslint/max-params":[`error`,{max:5}],"eslint/max-statements":[`error`,50],"eslint/no-console":[`error`,{allow:[`warn`,`error`,`info`]}],"eslint/no-warning-comments":[`error`,{terms:[`todo`,`fixme`,`xxx`,`hack`],location:`start`}],"eslint/no-param-reassign":`error`,"eslint/no-underscore-dangle":[`error`,{allow:[`__memoryInsightCardApplied`,`__memoryTdaiCardApplied`,`__sessionRescueApplied`,`__wukilDevToolsCardApplied`]}],"eslint/no-magic-numbers":`off`,"eslint/sort-keys":`off`,"eslint/sort-imports":`off`,"eslint/capitalized-comments":`off`,"eslint/no-ternary":`off`,"eslint/no-undefined":`off`,"eslint/no-void":`off`,"eslint/no-duplicate-imports":`off`,"eslint/require-await":`off`,"import/no-named-export":`off`,"import/group-exports":`off`,"import/exports-last":`off`,"import/prefer-default-export":`off`,"import/no-nodejs-modules":`off`,"import/no-relative-parent-imports":`off`,"import/max-dependencies":`off`,"import/no-default-export":`off`,"import/no-anonymous-default-export":`off`,"import/no-named-as-default-member":`off`,"import/consistent-type-specifier-style":[`error`,`prefer-top-level`],"import/no-duplicates":`error`,"import/no-cycle":`error`,"import/named":`error`,"import/first":`error`,"import/newline-after-import":`error`,"node/no-process-env":`off`,"node/no-sync":[`error`,{ignores:o}],"node/no-top-level-await":`error`,"oxc/no-async-await":`off`,"oxc/no-optional-chaining":`off`,"oxc/no-rest-spread-properties":`off`,"promise/always-return":`error`,"promise/no-promise-in-callback":[`error`,{exemptDeclarations:!0}],"promise/no-return-wrap":`error`,"promise/param-names":`error`,"promise/prefer-await-to-then":`error`,"typescript/consistent-type-imports":[`error`,{disallowTypeAnnotations:!1}],"typescript/explicit-function-return-type":[`error`,{allowDirectConstAssertionInArrowFunctions:!0,allowExpressions:!0,allowHigherOrderFunctions:!0,allowIIFEs:!0,allowTypedFunctionExpressions:!0,allowedNames:[`handler`,`callback`]}],"typescript/no-explicit-any":`error`,"typescript/no-floating-promises":`error`,"typescript/no-unsafe-assignment":`error`,"typescript/no-unsafe-type-assertion":`error`,"typescript/no-non-null-assertion":`error`,"typescript/require-await":`error`,"typescript/prefer-readonly-parameter-types":`off`,"typescript/promise-function-async":[`error`,{checkArrowFunctions:!1}],"typescript/consistent-return":[`error`,{treatUndefinedAsUnspecified:!0}],"typescript/only-throw-error":`error`,"unicorn/no-array-reduce":[`error`,{allowSimpleOperations:!0}],"unicorn/no-null":`off`,"unicorn/no-useless-undefined":[`error`,{checkArguments:!1}],"react/set-state-in-effect":`off`,"react/no-deriving-state-in-effects":`off`,"react/exhaustive-effect-dependencies":`off`,"react/hooks":`off`,"react/refs":`off`,"react/todo":`off`,...Object.fromEntries(h.map(e=>[e,`off`]))},v=[`**/*.test.ts`,`**/*.test.tsx`],y=[`**/__tests__/**/*.spec.ts`,`**/test/**/*.spec.ts`],b={files:[...v,`**/test/**`,`**/__tests__/**`],rules:{"typescript/no-non-null-assertion":`off`,"typescript/no-unsafe-type-assertion":`off`,"typescript/no-explicit-any":`off`,"typescript/require-await":`off`,"eslint/max-statements":`off`,"eslint/max-lines":`off`,"eslint/max-lines-per-function":`off`,"node/no-top-level-await":`off`}},x=[`expect`,`expectTypeOf`,`assert`,`assertType`],S=/^[A-Za-z_$][\w$]*$/u,C={files:[...v,...y],rules:{...Object.fromEntries(h.filter(e=>!g.has(e)).map(e=>[e,`error`])),"vitest/expect-expect":[`error`,{assertFunctionNames:x}],"react/rules-of-hooks":`off`}};function w(e={}){let t=e.assertionHelpers??[],n=e.titlePrefixes??[],r=[...t,...n].filter(e=>!S.test(e));if(r.length>0)throw Error(`assertionHelpers / titlePrefixes 只收裸标识符,不接受通配或带点形式(前者等于把 vitest/expect-expect 掏空):${r.join(`, `)}`);let i=[.../* @__PURE__ */ new Set([...x,...t])];return{...C,rules:{...C.rules,"vitest/expect-expect":[`error`,{assertFunctionNames:i}],...n.length===0?{}:{"vitest/prefer-lowercase-title":[`error`,{allowedPrefixes:[...new Set(n)]}]}}}}const T={files:[`scripts/**`,`*.mjs`,`*.mts`],rules:{"eslint/no-continue":`off`,"unicorn/max-nested-calls":`off`,"eslint/id-length":[`error`,{exceptions:[`a`,`i`,`t`,`x`,`y`,`z`,`n`,`p`,`s`,`v`,`e`,`f`,`ok`,`fs`,`id`]}],"unicorn/no-process-exit":`off`,"unicorn/no-useless-undefined":`off`,"typescript/no-non-null-assertion":`off`,"node/no-sync":`off`,"node/no-top-level-await":`off`,"typescript/no-unsafe-member-access":`off`,"typescript/no-unsafe-call":`off`,"typescript/no-unsafe-assignment":`off`,"typescript/no-unsafe-return":`off`,"typescript/no-unsafe-argument":`off`,"typescript/strict-boolean-expressions":`off`,"typescript/no-implied-eval":`off`,"typescript/require-array-sort-compare":`off`}};function E(e){let t={...i,...e};return e=>{let n=t[e];if(n!==void 0)return n;let r=e.indexOf(`/`);return r===-1?void 0:t[`${e.slice(0,r)}/*`]}}function D(e,t,n){if(t===void 0)return;let r=[];for(let[e,i]of Object.entries(t))if((Array.isArray(i)?i[0]:i)===`off`){let t=n(e);(t===void 0||t.note.trim().length===0)&&r.push(e)}if(r.length>0)throw Error(`${e} 里这些规则被关成 off 但没有依据(OFF_JUSTIFICATIONS 查不到,或 note 为空):${r.join(`, `)}。要么在代码里修,要么给它补一条 kind + measured + note。`)}function O(e={}){let{syncWrites:n=[],extraRules:r={},extraOverrides:i=[],extraIgnorePatterns:a=[],jsPlugins:c,offReasons:l={},assertionHelpers:h=[],titlePrefixes:g=[]}=e,v=E(l),y={..._,...d,...n.length>0?{"node/no-sync":[`error`,{ignores:[.../* @__PURE__ */ new Set([...o,...n])]}]}:{},...r},x=[b,w({assertionHelpers:h,titlePrefixes:g}),T,...i];D(`rules`,y,v);for(let[e,t]of x.entries())D(`overrides[${e}]`,t.rules,v);return t({plugins:s,env:{node:!0,es2024:!0,browser:!0},options:p,categories:f,ignorePatterns:[...m,...a],jsPlugins:u(c),rules:y,overrides:x})}export{_ as BASE_RULES,i as OFF_JUSTIFICATIONS,o as READONLY_SYNC_ALLOWLIST,a as RETIRED_OFFS,T as SCRIPTS_OVERRIDES,C as TEST_FILE_OVERRIDES,b as TEST_OVERRIDES,h as VITEST_ALL_RULES,x as VITEST_ASSERTION_DEFAULTS,O as definePluginConfig,w as makeTestFileOverrides,u as resolveJsPlugins};
1
+ import{createRequire as e}from"node:module";import{defineConfig as t}from"oxlint";function n(e){return(typeof e==`string`?e:`${e.name} ${e.specifier}`).includes(`sonarjs`)}const r=`同 no-unsafe-member-access`,i={"vitest/*":{kind:`仅限特定文件`,measured:7,note:`用例结构类判断在非用例文件上无从计算`},"vitest/no-hooks":{kind:`上游不推荐`,measured:181,note:`禁用 hook 本身;本仓按官方 vitest 用法大量使用 before*/after*`},"vitest/no-conditional-in-test":{kind:`仅限特定文件`,measured:523,note:`平台/宿主版本分支是刻意的(macOS 与 Linux 的家目录形态、0.1.7 与 0.1.6 的 API 差异)`},"vitest/max-expects":{kind:`上游不推荐`,measured:163,note:`给单条用例的断言条数设上限属风格偏好,不指向缺陷`},"vitest/prefer-expect-assertions":{kind:`上游不推荐`,measured:2902,note:`要求每个 async 用例手写 expect.assertions(n),是与断言强度无关的计数要求`},"vitest/require-test-timeout":{kind:`上游不推荐`,measured:2892,note:`要求每条用例显式 timeout;本仓用泵式假时钟,超时由 13 份 vitest 配置统一给出`},"vitest/prefer-importing-vitest-globals":{kind:`实测有害`,measured:0,note:`autofix 方向是删掉显式 import 改回裸全局;13 份 vitest 配置都没开 globals:true,应用后立即出现 3605 处 TS2593、测试全部失效`},"vitest/no-importing-vitest-globals":{kind:`实测有害`,measured:133,note:`与上一条同族、方向相反,两条同时开启就是把两种写法都判违规`},"vitest/prefer-import-in-mock":{kind:`实测有害`,measured:6,note:"动态形态按完整模块导出校验工厂返回值,而 @types/node 的 os、@types/react 都是 `export =` 形状、类型上没有 default;实测三处 TS2769+TS2740/2741,react 那处无论怎么展开都补不出 default"},"vitest/prefer-lowercase-title":{kind:`仅限特定文件`,measured:171,note:`只在用例文件里生效:它带 autofix,实测一轮 oxlint --fix 静默把 260 条标题改成了小写(含 nO_VERIFY 这种坏名字)。包级 titlePrefixes 只留真正的技术名(GET/CSRF/组件名…):非技术名(工单号一类)不该借这条豁免留在标题里,而中文开头的标题天然满足要求(无大小写),免检范围能收多小就收多小。实测 oxlint 前缀一命中就把整条标题免检,所以陈旧条目由配置基线自检按『免检范围未被使用』指出,不靠人工巡检`},"vitest/prefer-called-times":{kind:`与已启用规则互斥`,measured:0,note:`实测核对(同文件四种写法各跑一次):toHaveBeenCalledTimes(1) 被 prefer-called-once 判违规、toHaveBeenCalledOnce() 被本条判违规、expect(spy.mock.calls).toHaveLength(1) 被 prefer-to-have-been-called-times 判违规,只有 n>=2 能同时满足三条 ⇒ 三条同开等于「单次调用」这条断言无法书写(实测逼得消费方改用 assert.equal(spy.mock.calls.length, 1) 绕行)。保留 prefer-called-once 与 prefer-to-have-been-called-times 两条方向一致的组合,关闭本条`},"vitest/prefer-describe-function-title":{kind:`与已启用规则互斥`,measured:48,note:"要求 `describe(fn)`,而 valid-title 要求字符串字面量(oxlint 1.85 的 valid-title 是 DummyRule、无任何选项);上游 recommended 收的是 valid-title,取它,26 处 `describe(fn)` 按代码改成同名字符串"},"vitest/prefer-to-be-truthy":{kind:`实测有害`,measured:117,note:`把 toStrictEqual(true) 放宽成 toTruthy(),接受任意真值是削弱断言`},"vitest/prefer-to-be-falsy":{kind:`实测有害`,measured:89,note:`同族,放宽成 toFalsy() 同样是削弱断言`},"import/no-default-export":{kind:`与官方形态冲突`,measured:38,note:`官方 cordis 入口就是 default export(vendor/loader/src/index.ts 的 unwrapExports 先 unwrap default),12 条正是 12 个 bundle 入口`},"import/no-named-export":{kind:`与官方形态冲突`,measured:895,note:`13 个包与上游 deepseek-harness 一样以具名导出 + 子路径说明符对外提供接口`},"import/prefer-default-export":{kind:`与官方形态冲突`,measured:58,note:`与 no-default-export 同族、方向与 cordis 入口相反`},"import/no-nodejs-modules":{kind:`与官方形态冲突`,measured:448,note:"宿主侧就运行在 node 上,`node:` 内置模块是运行环境本身而不是越界"},"import/no-named-as-default-member":{kind:`与官方形态冲突`,measured:47,note:`对具名导出的默认对象做成员访问是本仓消费官方声明的常态`},"import/no-anonymous-default-export":{kind:`与官方形态冲突`,measured:12,note:`官方 cordis 入口是匿名对象 default export(registry.ts 的 RegistryService.plugin() 读 name/Config,isApplicable() 判 apply),改成具名等于改官方形态`},"eslint/no-duplicate-imports":{kind:`实测有害`,measured:166,note:`ESLint 官方已废弃(不区分 import type),由 import/no-duplicates 取代`},"import/group-exports":{kind:`上游不推荐`,measured:766,note:`要求单点导出,与具名导出的接口形态冲突`},"import/exports-last":{kind:`上游不推荐`,measured:528,note:`要求导出语句在文件末尾`},"import/no-relative-parent-imports":{kind:`上游不推荐`,measured:277,note:`包内 lib/ 与 test/ 的相对父级引用是既有结构`},"import/max-dependencies":{kind:`上游不推荐`,measured:25,note:`给 import 条数设上限;宿主侧消费官方服务天然依赖多`},"node/no-process-env":{kind:`上游不推荐`,measured:51,note:`环境变量是本仓的输入来源(DSH_HOME、profile 目录、构建期开关);eslint-plugin-n 的 recommended 也不含本条`},"eslint/no-magic-numbers":{kind:`上游不推荐`,measured:5774,note:`把 HTTP 状态码/毫秒阈值抽成常量的计数规则`},"eslint/sort-keys":{kind:`上游不推荐`,measured:4101,note:`对象键排序;成对字面量与 locale 字典的可读性会一起受损`},"eslint/sort-imports":{kind:`上游不推荐`,measured:675,note:`字母序 import,与 oxfmt 的分组形态冲突`},"eslint/capitalized-comments":{kind:`上游不推荐`,measured:2388,note:`本仓注释以中文为主,「首字母大写」对中文注释无从判定`},"eslint/no-ternary":{kind:`上游不推荐`,measured:1024,note:`禁三元;改写成 if/else 并不会更正确`},"eslint/no-undefined":{kind:`上游不推荐`,measured:2009,note:"禁 `undefined` 字面量,与本仓大量显式可选返回形态冲突"},"eslint/no-void":{kind:`上游不推荐`,measured:172,note:"禁 `void` 前缀,而 `void promise` 正是满足 no-floating-promises 的官方写法"},"unicorn/no-null":{kind:`上游不推荐`,measured:788,note:`禁 null;官方声明与 JSON 边界大量用 null,改成 undefined 会改变序列化形态`},"typescript/prefer-readonly-parameter-types":{kind:`上游不推荐`,measured:2433,note:`要求每个入参类型全 readonly;官方声明(SessionEvent/ConfigForm 等)是可变的,改不动也不该改`},"oxc/no-async-await":{kind:`与已启用规则互斥`,measured:2160,note:`禁 async/await,而同表里 promise-function-async、require-await、no-floating-promises 都在要求用 async`},"oxc/no-optional-chaining":{kind:`与已启用规则互斥`,measured:1354,note:"禁 `?.`,而 typescript/prefer-optional-chain 正在要求把 && 链改成 `?.`"},"oxc/no-rest-spread-properties":{kind:`与已启用规则互斥`,measured:550,note:`禁对象 spread,而 ES2024 目标与官方声明的投影写法都靠它`},"typescript/no-explicit-any":{kind:`仅限特定文件`,measured:1,note:`用例里的桩件面(mini-react 之类)需要 any 才塞得进官方签名`},"typescript/no-non-null-assertion":{kind:`仅限特定文件`,measured:536,note:"用例里 `!` 是「前驱条件已成立」的最短写法"},"typescript/no-unsafe-type-assertion":{kind:`仅限特定文件`,measured:844,note:"桩件需要 `as never` / `as unknown as` 跨官方名义类型"},"typescript/require-await":{kind:`仅限特定文件`,measured:467,note:`官方 async 契约的同步实现与测试替身撑不住这条;prod 侧的条数按代码修,不进豁免`},"eslint/require-await":{kind:`与官方形态冲突`,measured:481,note:`它与 typescript/require-await 是同一条判断的两份实现,不是两条:实测核对(一段无 await 的 async 函数、--type-aware)单开各自都报、同开报两次,即 2 errors / 1 defect。按 typescript-eslint 官方对 extension rule 的处理方式裁决:留带类型信息的扩展那条、关基线那条。覆盖范围没有因此变小:全仓逐行去重实测 514 行两点同报、typescript 独有 0 行、eslint 独有只落在用例范围与配置自身的中间态;而 --type-aware 实测对 .mjs 也会由扩展那条报出,所以 scripts/*.mjs 面不需要基线那条补位。用例文件由 TEST_OVERRIDES 整族豁免`},"eslint/max-statements":{kind:`仅限特定文件`,measured:549,note:`用例体天然长(given/when/then 展开)`},"eslint/max-lines-per-function":{kind:`仅限特定文件`,measured:365,note:`同上`},"eslint/max-lines":{kind:`仅限特定文件`,measured:54,note:`单个用例文件的长度不作为缺陷信号`},"node/no-sync":{kind:`仅限特定文件`,measured:299,note:`构建脚本与门禁脚本按设计同步读;生产代码的写侧由每包 syncWrites 逐项登记,不在豁免里`},"node/no-top-level-await":{kind:`仅限特定文件`,measured:53,note:`脚本以 node 直接执行,顶层 await 是 ESM 常态;prod 侧 0 条`},"typescript/strict-boolean-expressions":{kind:`仅限特定文件`,measured:0,note:`scripts/*.mjs 无类型面,隐式 any 上无从判定`},"typescript/no-implied-eval":{kind:`仅限特定文件`,measured:0,note:`同上:这条要类型信息才能判`},"typescript/no-unsafe-member-access":{kind:`仅限特定文件`,measured:0,note:`无类型标注的脚本里每个值都落进隐式 any`},"typescript/no-unsafe-call":{kind:`仅限特定文件`,measured:0,note:r},"typescript/no-unsafe-assignment":{kind:`仅限特定文件`,measured:0,note:r},"typescript/no-unsafe-return":{kind:`仅限特定文件`,measured:0,note:r},"typescript/no-unsafe-argument":{kind:`仅限特定文件`,measured:0,note:r},"typescript/require-array-sort-compare":{kind:`仅限特定文件`,measured:0,note:`无类型脚本里「比较器缺失」判不出来`},"unicorn/no-process-exit":{kind:`仅限特定文件`,measured:2,note:`CLI 脚本的 process.exit 就是它的返回方式`},"eslint/no-continue":{kind:`仅限特定文件`,measured:53,note:`只对 scripts/ 豁免:TS 侧实测 0 条(包代码本来就不用 continue),908 行的门禁脚本改成嵌套 if 只会更难读`},"unicorn/max-nested-calls":{kind:`仅限特定文件`,measured:59,note:`只对 scripts/ 豁免:TS 侧实测 0 条;CLI 脚本里链式 map/filter/join 的深度由数据形状决定,不指向缺陷`},"unicorn/no-useless-undefined":{kind:`仅限特定文件`,measured:0,note:`脚本侧同上调;prod 仍按配置项 checkArguments:false 生效`},"react/set-state-in-effect":{kind:`与官方形态冲突`,measured:16,note:`卡片用 effect 同步宿主态到 store 是挂载适配器形态;Compiler 建议的 render 期推导要改写 12 份适配器的状态流`},"react/no-deriving-state-in-effects":{kind:`与官方形态冲突`,measured:7,note:`适配器形态里「props/state 派生值在 effect 对齐宿主」是挂载动作,不是可下沉到 render 的纯派生`},"react/exhaustive-effect-dependencies":{kind:`与官方形态冲突`,measured:8,note:`Compiler 版依赖审计对适配器的内联闭包全量追问;与 react-hooks/exhaustive-deps(保留并已修)形成双门,留后者`},"react/hooks":{kind:`与官方形态冲突`,measured:13,note:`「同一 hook 函数跨渲染同引用」在适配器的内联闭包形态下整体不成立;收敛批次把闭包提升后再回来开`},"react/refs":{kind:`与官方形态冲突`,measured:1,note:`挂载适配器在 render 期读 ref 对齐宿主布局;收敛批次改成挂载后读`},"react/todo":{kind:`上游不推荐`,measured:6,note:`报的是 React 编译器 BuildHIR 自己不支持 try/catch(-finally) 的上游 TODO,不是代码缺陷`},"react/rules-of-hooks":{kind:`仅限特定文件`,measured:3,note:`只对用例文件豁免(TEST_FILE_OVERRIDES):测试架在组件树外直接驱动卡片适配 hook(useCardOf / useSyncExternalStore 桩),调用次数顺序由桩件固定。键用表载前缀 react/(诊断文案显示 react-hooks(...) 是显示名,配置键以 --rules 的 Source 列为准)`}},a=[`typescript/no-empty-object-type`],o=[`existsSync`,`readFileSync`,`readdirSync`,`readSync`,`realpathSync`,`statSync`],s=[`eslint`,`typescript`,`unicorn`,`oxc`,`node`,`promise`,`vitest`,`import`,`react`,`jsx-a11y`],c=[`eslint-plugin-sonarjs`,`eslint-plugin-sonarjs/cjs/plugin.js`];function l(){let t=e(import.meta.url),n=[];for(let e of c)try{return t.resolve(e)}catch{n.push(e)}throw Error(`oxlint 基线要挂 eslint-plugin-sonarjs,但从本包解析不到它(试过 ${n.join(`、`)})。要么在本包 devDependencies 里装 eslint-plugin-sonarjs,要么把你自己解析到的 sonarjs 入口经 definePluginConfig({ jsPlugins: [...] }) 传进来(入口路径须指向 sonarjs:SONARJS_RULES 无条件引用它,换成别家的插件无法满足这一条)。`)}function u(e,t=l){let r=e??[],i=null;try{i=t()}catch(e){if(!r.some(e=>n(e)))throw e}return i===null?[...r]:[i,...r.filter(e=>e!==i)]}const d={"sonarjs/no-identical-functions":`error`,"sonarjs/no-duplicated-branches":`error`,"sonarjs/no-all-duplicated-branches":`error`,"sonarjs/no-collapsible-if":`error`,"sonarjs/no-identical-conditions":`error`,"sonarjs/no-identical-expressions":`error`,"sonarjs/no-duplicate-string":`error`,"sonarjs/cognitive-complexity":`error`,"sonarjs/max-switch-cases":`error`,"sonarjs/no-inverted-boolean-check":`error`,"sonarjs/no-duplicate-in-composite":`error`,"sonarjs/duplicates-in-character-class":`error`,"sonarjs/no-useless-catch":`error`,"sonarjs/no-extra-arguments":`error`,"sonarjs/no-redundant-assignments":`error`,"sonarjs/prefer-single-boolean-return":`error`,"sonarjs/label-position":`error`},f={correctness:`error`,suspicious:`error`,style:`error`,perf:`error`,restriction:`error`,pedantic:`error`,nursery:`error`},p={typeAware:!0,typeCheck:!0,denyWarnings:!0,maxWarnings:0,reportUnusedDisableDirectives:`error`,respectEslintDisableDirectives:!1},m=[`**/node_modules/**`,`.toolchain/**`,`coverage/**`,`dist/**`,`client.js`,`host.js`],h=/* @__PURE__ */ `vitest/consistent-each-for.vitest/consistent-test-filename.vitest/consistent-test-it.vitest/consistent-vitest-vi.vitest/expect-expect.vitest/hoisted-apis-on-top.vitest/max-expects.vitest/max-nested-describe.vitest/no-alias-methods.vitest/no-commented-out-tests.vitest/no-conditional-expect.vitest/no-conditional-in-test.vitest/no-conditional-tests.vitest/no-disabled-tests.vitest/no-duplicate-hooks.vitest/no-focused-tests.vitest/no-hooks.vitest/no-identical-title.vitest/no-import-node-test.vitest/no-importing-vitest-globals.vitest/no-interpolation-in-snapshots.vitest/no-large-snapshots.vitest/no-mocks-import.vitest/no-restricted-matchers.vitest/no-restricted-vi-methods.vitest/no-standalone-expect.vitest/no-test-prefixes.vitest/no-test-return-statement.vitest/no-unneeded-async-expect-function.vitest/padding-around-after-all-blocks.vitest/padding-around-test-blocks.vitest/prefer-called-exactly-once-with.vitest/prefer-called-once.vitest/prefer-called-times.vitest/prefer-called-with.vitest/prefer-comparison-matcher.vitest/prefer-describe-function-title.vitest/prefer-each.vitest/prefer-equality-matcher.vitest/prefer-expect-assertions.vitest/prefer-expect-resolves.vitest/prefer-expect-type-of.vitest/prefer-hooks-in-order.vitest/prefer-hooks-on-top.vitest/prefer-import-in-mock.vitest/prefer-importing-vitest-globals.vitest/prefer-lowercase-title.vitest/prefer-mock-promise-shorthand.vitest/prefer-mock-return-shorthand.vitest/prefer-snapshot-hint.vitest/prefer-spy-on.vitest/prefer-strict-boolean-matchers.vitest/prefer-strict-equal.vitest/prefer-to-be.vitest/prefer-to-be-falsy.vitest/prefer-to-be-object.vitest/prefer-to-be-truthy.vitest/prefer-to-contain.vitest/prefer-to-have-been-called-times.vitest/prefer-to-have-length.vitest/prefer-todo.vitest/require-awaited-expect-poll.vitest/require-hook.vitest/require-local-test-context-for-concurrent-snapshots.vitest/require-mock-type-parameters.vitest/require-test-timeout.vitest/require-to-throw-message.vitest/require-top-level-describe.vitest/valid-describe-callback.vitest/valid-expect.vitest/valid-expect-in-promise.vitest/valid-title.vitest/warn-todo`.split(`.`),g=/* @__PURE__ */ new Set([`vitest/max-expects`,`vitest/no-conditional-in-test`,`vitest/no-hooks`,`vitest/no-importing-vitest-globals`,`vitest/prefer-called-times`,`vitest/prefer-describe-function-title`,`vitest/prefer-expect-assertions`,`vitest/prefer-import-in-mock`,`vitest/prefer-importing-vitest-globals`,`vitest/prefer-to-be-falsy`,`vitest/prefer-to-be-truthy`,`vitest/require-test-timeout`]),_={"eslint/one-var":[`error`,`never`],"eslint/func-style":[`error`,`declaration`,{allowArrowFunctions:!0,overrides:{namedExports:`ignore`}}],"eslint/id-length":[`error`,{exceptions:[`a`,`i`,`t`,`x`,`y`,`z`]}],"eslint/init-declarations":[`error`,`never`,{ignoreForLoopInit:!0}],"eslint/max-lines":[`error`,{max:2e3,skipBlankLines:!0,skipComments:!0}],"eslint/max-lines-per-function":[`error`,{max:120,skipBlankLines:!0,skipComments:!0}],"eslint/complexity":`error`,"eslint/max-params":[`error`,{max:5}],"eslint/max-statements":[`error`,50],"eslint/no-console":[`error`,{allow:[`warn`,`error`,`info`]}],"eslint/no-warning-comments":[`error`,{terms:[`todo`,`fixme`,`xxx`,`hack`],location:`start`}],"eslint/no-param-reassign":`error`,"eslint/no-underscore-dangle":[`error`,{allow:[`__memoryInsightCardApplied`,`__memoryTdaiCardApplied`,`__sessionRescueApplied`,`__wukilDevToolsCardApplied`]}],"eslint/no-magic-numbers":`off`,"eslint/sort-keys":`off`,"eslint/sort-imports":`off`,"eslint/capitalized-comments":`off`,"eslint/no-ternary":`off`,"eslint/no-undefined":`off`,"eslint/no-void":`off`,"eslint/no-duplicate-imports":`off`,"eslint/require-await":`off`,"import/no-named-export":`off`,"import/group-exports":`off`,"import/exports-last":`off`,"import/prefer-default-export":`off`,"import/no-nodejs-modules":`off`,"import/no-relative-parent-imports":`off`,"import/max-dependencies":`off`,"import/no-default-export":`off`,"import/no-anonymous-default-export":`off`,"import/no-named-as-default-member":`off`,"import/consistent-type-specifier-style":[`error`,`prefer-top-level`],"import/no-duplicates":`error`,"import/no-cycle":`error`,"import/named":`error`,"import/first":`error`,"import/newline-after-import":`error`,"node/no-process-env":`off`,"node/no-sync":[`error`,{ignores:o}],"node/no-top-level-await":`error`,"oxc/no-async-await":`off`,"oxc/no-optional-chaining":`off`,"oxc/no-rest-spread-properties":`off`,"promise/always-return":`error`,"promise/no-promise-in-callback":[`error`,{exemptDeclarations:!0}],"promise/no-return-wrap":`error`,"promise/param-names":`error`,"promise/prefer-await-to-then":`error`,"typescript/consistent-type-imports":[`error`,{disallowTypeAnnotations:!1}],"typescript/explicit-function-return-type":[`error`,{allowDirectConstAssertionInArrowFunctions:!0,allowExpressions:!0,allowHigherOrderFunctions:!0,allowIIFEs:!0,allowTypedFunctionExpressions:!0,allowedNames:[`handler`,`callback`]}],"typescript/no-explicit-any":`error`,"typescript/no-floating-promises":`error`,"typescript/no-unsafe-assignment":`error`,"typescript/no-unsafe-type-assertion":`error`,"typescript/no-non-null-assertion":`error`,"typescript/require-await":`error`,"typescript/prefer-readonly-parameter-types":`off`,"typescript/promise-function-async":[`error`,{checkArrowFunctions:!1}],"typescript/consistent-return":[`error`,{treatUndefinedAsUnspecified:!0}],"typescript/only-throw-error":`error`,"unicorn/no-array-reduce":[`error`,{allowSimpleOperations:!0}],"unicorn/no-null":`off`,"unicorn/no-useless-undefined":[`error`,{checkArguments:!1}],"react/set-state-in-effect":`off`,"react/no-deriving-state-in-effects":`off`,"react/exhaustive-effect-dependencies":`off`,"react/hooks":`off`,"react/refs":`off`,"react/todo":`off`,...Object.fromEntries(h.map(e=>[e,`off`]))},v=[`**/*.test.ts`,`**/*.test.tsx`],y=[`**/__tests__/**/*.spec.ts`,`**/test/**/*.spec.ts`],b={files:[...v,`**/test/**`,`**/__tests__/**`],rules:{"typescript/no-non-null-assertion":`off`,"typescript/no-unsafe-type-assertion":`off`,"typescript/no-explicit-any":`off`,"typescript/require-await":`off`,"eslint/max-statements":`off`,"eslint/max-lines":`off`,"eslint/max-lines-per-function":`off`,"node/no-top-level-await":`off`}},x=[`expect`,`expectTypeOf`,`assert`,`assertType`],S=/^[A-Za-z_$][\w$]*$/u,C={files:[...v,...y],rules:{...Object.fromEntries(h.filter(e=>!g.has(e)).map(e=>[e,`error`])),"vitest/expect-expect":[`error`,{assertFunctionNames:x}],"react/rules-of-hooks":`off`}};function w(e={}){let t=e.assertionHelpers??[],n=e.titlePrefixes??[],r=[...t,...n].filter(e=>!S.test(e));if(r.length>0)throw Error(`assertionHelpers / titlePrefixes 只收裸标识符,不接受通配或带点形式(前者等于让 vitest/expect-expect 失去作用):${r.join(`, `)}`);let i=[.../* @__PURE__ */ new Set([...x,...t])];return{...C,rules:{...C.rules,"vitest/expect-expect":[`error`,{assertFunctionNames:i}],...n.length===0?{}:{"vitest/prefer-lowercase-title":[`error`,{allowedPrefixes:[...new Set(n)]}]}}}}const T={files:[`scripts/**`,`*.mjs`,`*.mts`],rules:{"eslint/no-continue":`off`,"unicorn/max-nested-calls":`off`,"eslint/id-length":[`error`,{exceptions:[`a`,`i`,`t`,`x`,`y`,`z`,`n`,`p`,`s`,`v`,`e`,`f`,`ok`,`fs`,`id`]}],"unicorn/no-process-exit":`off`,"unicorn/no-useless-undefined":`off`,"typescript/no-non-null-assertion":`off`,"node/no-sync":`off`,"node/no-top-level-await":`off`,"typescript/no-unsafe-member-access":`off`,"typescript/no-unsafe-call":`off`,"typescript/no-unsafe-assignment":`off`,"typescript/no-unsafe-return":`off`,"typescript/no-unsafe-argument":`off`,"typescript/strict-boolean-expressions":`off`,"typescript/no-implied-eval":`off`,"typescript/require-array-sort-compare":`off`}};function E(e){let t={...i,...e};return e=>{let n=t[e];if(n!==void 0)return n;let r=e.indexOf(`/`);return r===-1?void 0:t[`${e.slice(0,r)}/*`]}}function D(e,t,n){if(t===void 0)return;let r=[];for(let[e,i]of Object.entries(t))if((Array.isArray(i)?i[0]:i)===`off`){let t=n(e);(t===void 0||t.note.trim().length===0)&&r.push(e)}if(r.length>0)throw Error(`${e} 里这些规则被关成 off 但没有依据(OFF_JUSTIFICATIONS 查不到,或 note 为空):${r.join(`, `)}。要么在代码里修,要么给它补一条 kind + measured + note。`)}function O(e={}){let{syncWrites:n=[],extraRules:r={},extraOverrides:i=[],extraIgnorePatterns:a=[],jsPlugins:c,offReasons:l={},assertionHelpers:h=[],titlePrefixes:g=[]}=e,v=E(l),y={..._,...d,...n.length>0?{"node/no-sync":[`error`,{ignores:[.../* @__PURE__ */ new Set([...o,...n])]}]}:{},...r},x=[b,w({assertionHelpers:h,titlePrefixes:g}),T,...i];D(`rules`,y,v);for(let[e,t]of x.entries())D(`overrides[${e}]`,t.rules,v);return t({plugins:s,env:{node:!0,es2024:!0,browser:!0},options:p,categories:f,ignorePatterns:[...m,...a],jsPlugins:u(c),rules:y,overrides:x})}export{_ as BASE_RULES,i as OFF_JUSTIFICATIONS,o as READONLY_SYNC_ALLOWLIST,a as RETIRED_OFFS,T as SCRIPTS_OVERRIDES,C as TEST_FILE_OVERRIDES,b as TEST_OVERRIDES,h as VITEST_ALL_RULES,x as VITEST_ASSERTION_DEFAULTS,O as definePluginConfig,w as makeTestFileOverrides,u as resolveJsPlugins};
@@ -1 +1 @@
1
- import{defineConfig as e}from"vitest/config";const t={provider:`v8`,exclude:[`test/**`,`node_modules/**`,`**/test/**`,`**/node_modules/**`,`build-client*`,`client.js`,`agents/**`,`scripts/**`,`**/*.d.ts`,`**/*.d.mts`],reporter:[`text`,`json-summary`,`json`],reportsDirectory:`coverage`,thresholds:{lines:100,statements:100,functions:100,branches:100}};function n(n){let{coverageInclude:r,coverage:i,test:a}=n;if(r.length===0||r.some(e=>e.trim().length===0))throw Error(`coverageInclude 不能为空数组,也不能含空串:统计面缺件后覆盖率阈值照样全绿,缺的是判据不是覆盖。`);if(a&&`coverage`in a)throw Error(`test.coverage 会整块替换公共覆盖率面(含四项 100% 阈值与排除表);覆盖率覆盖项请走 coverage 参数,逐键合并。`);return e({test:{include:[`test/**/*.{test,spec}.{ts,tsx,mts,cts}`],environment:`node`,testTimeout:2e4,coverage:{...t,...i,include:r,thresholds:{...t.thresholds,...i?.thresholds}},...a}})}export{n as definePackageConfig};
1
+ import{defineConfig as e}from"vitest/config";const t={provider:`v8`,exclude:[`test/**`,`node_modules/**`,`**/test/**`,`**/node_modules/**`,`build-client*`,`client.js`,`agents/**`,`scripts/**`,`**/*.d.ts`,`**/*.d.mts`],reporter:[`text`,`json-summary`,`json`],reportsDirectory:`coverage`,thresholds:{lines:100,statements:100,functions:100,branches:100}};function n(n){let{coverageInclude:r,coverage:i,test:a}=n;if(r.length===0||r.some(e=>e.trim().length===0))throw Error(`coverageInclude 不能为空数组,也不能含空串:统计范围缺件后覆盖率阈值照样全部通过,缺的是测量对象不是覆盖。`);if(a&&`coverage`in a)throw Error(`test.coverage 会整块替换公共覆盖率配置(含四项 100% 阈值与排除表);覆盖率覆盖项请走 coverage 参数,逐键合并。`);return e({test:{include:[`test/**/*.{test,spec}.{ts,tsx,mts,cts}`],environment:`node`,testTimeout:2e4,coverage:{...t,...i,include:r,thresholds:{...t.thresholds,...i?.thresholds}},...a}})}export{n as definePackageConfig};
@@ -6,7 +6,7 @@ import type { InputOptions } from "rolldown";
6
6
  */
7
7
  export declare function isRecord(raw: unknown): raw is Record<string, unknown>;
8
8
  /**
9
- * 从 JSON.parse 的 unknown 投影为 Record(非对象 → 空对象兜底),避免 any 索引。
9
+ * 从 JSON.parse 的 unknown 投影为 Record(非对象 → 空对象回退),避免 any 索引。
10
10
  * @param raw - JSON.parse 之后的任意值
11
11
  * @returns 普通对象;输入不是对象时为空对象
12
12
  */
@@ -16,7 +16,7 @@ export declare function asRecord(raw: unknown): Record<string, unknown>;
16
16
  *
17
17
  * 惰性(调用时才读)而不是在消费方模块顶层读:顶层一次 JSON 语法错误会以未捕获的顶层
18
18
  * await 错误 + 裸 SyntaxError 收场,读者看不出是哪个文件坏了;而测试 import 构建模块时
19
- * 只为拿构建函数,不该连带付一次磁盘 I/O。
19
+ * 只为拿构建函数,不该连带做一次磁盘 I/O。
20
20
  * @param root - 包根绝对路径
21
21
  * @returns 解析后的 manifest
22
22
  */
@@ -31,7 +31,7 @@ export declare function readManifest(root: string): Promise<unknown>;
31
31
  export declare function packageNameOf(id: string): string;
32
32
  /**
33
33
  * rolldown 输出项的最小投影:单文件产物只关心这几项。
34
- * `moduleIds` 之类不进投影——本类型只判形状,多一层声明就多一处与 rolldown 版本耦合的面,
34
+ * `moduleIds` 之类不进投影——本类型只判形状,多一层声明就多一处与 rolldown 版本耦合的地方,
35
35
  * 而调用方拿到的仍是原始输出项,不缺字段。
36
36
  */
37
37
  export interface OutputItem {
@@ -42,17 +42,17 @@ export interface OutputItem {
42
42
  readonly moduleIds?: readonly string[] | undefined;
43
43
  }
44
44
  /**
45
- * 单文件产物只允许一个 entry chunk:多余 chunk / asset 不落盘,产物要到运行时才因缺模块而炸。
45
+ * 单文件产物只允许一个 entry chunk:多余 chunk / asset 不写入磁盘,产物要到运行时才因缺模块而报错。
46
46
  * 这是「静默不渲染」同一类难查故障,所以在构建期就失败。
47
47
  * @param output - rolldown 的 generate 输出清单
48
- * @param source - 入口源码名(错误信息点名用)
48
+ * @param source - 入口源码名(供错误信息指出出处)
49
49
  * @returns 唯一的那个 entry chunk
50
50
  */
51
51
  export declare function singleEntryChunk(output: readonly OutputItem[], source: string): OutputItem & {
52
52
  code: string;
53
53
  };
54
54
  /**
55
- * 原子落盘:目标目录下 `.tmp/` 草稿 + rename;失败时清掉草稿再抛。
55
+ * 原子写入:目标目录下 `.tmp/` 草稿 + rename;失败时清掉草稿再抛。
56
56
  *
57
57
  * 草稿落在**目标文件所在目录**下的 `.tmp/`,不是 `os.tmpdir()`,也不是产物旁边的裸名:
58
58
  * - 不用 `os.tmpdir()`:rename 只在同一文件系统内原子,跨设备会以 EXDEV 失败,而系统临时
@@ -63,16 +63,16 @@ export declare function singleEntryChunk(output: readonly OutputItem[], source:
63
63
  * 统一忽略的目录,不需要为构建残留单独扩忽略规则。
64
64
  *
65
65
  * 失败信息带上两个路径并保留 cause:裸 `ENOENT … open '…/<uuid>.tmp'` 把注意力引到草稿名上,
66
- * 读者还得自己剥出真正的产物路径。
66
+ * 读者还得自己从中找出真正的产物路径。
67
67
  * @param target - 目标文件绝对路径
68
68
  * @param text - 产物正文
69
69
  */
70
70
  export declare function writeArtifact(target: string, text: string): Promise<void>;
71
- /** 异常路径上释放 rolldown bundle 的最小形状。 */
71
+ /** 异常路径上释放 rolldown bundle 的最小接口。 */
72
72
  export interface CloseableBundle {
73
73
  readonly close: () => Promise<void>;
74
74
  }
75
- /** generate 交给调用方的最小输出形状(属性式签名,真实 bundle 结构满足)。 */
75
+ /** generate 交给调用方的最小输出结构(属性式签名,真实 bundle 结构满足)。 */
76
76
  export interface RolldownBundle extends CloseableBundle {
77
77
  readonly generate: (options: {
78
78
  format: "esm" | "cjs";
@@ -94,8 +94,8 @@ export type RolldownFactory = (options: InputOptions) => Promise<RolldownBundle>
94
94
  * 异常路径上释放 rolldown bundle:close 失败只记日志,不覆盖调用方正在抛的原始错因。
95
95
  *
96
96
  * bundle 持有原生资源,generate 或输出守卫抛错时同样要释放;但那时唯一有价值的日志是
97
- * 「构建为什么失败」,让一条关于资源释放的噪音顶掉它,排障就从「读一行」变成「猜」。
98
- * 成功路径不要用本函数:那里 close 失败仍应判红,资源没释放是构建器的问题。
97
+ * 「构建为什么失败」,让一条与错因无关的资源释放日志盖过它,排障就从「读一行」变成「猜」。
98
+ * 成功路径不要用本函数:那里 close 失败仍应判定失败,资源没释放是构建器的问题。
99
99
  * @param bundle - 待释放的 bundle
100
100
  */
101
101
  export declare function closeQuietly(bundle: CloseableBundle): Promise<void>;
@@ -1,46 +1,46 @@
1
1
  import type { RolldownFactory } from "./build-artifacts.js";
2
2
  /**
3
3
  * 宿主 seed 表里 react 家族的全部说明符(客户端产物只外置宿主真给得出的模块)。
4
- * 与宿主客户端自己的模块表同源:那张表里 react 家族只有这四条。外置面更大的包
4
+ * 与宿主客户端自己的模块表同源:那张表里 react 家族只有这四条。外置清单更大的包
5
5
  * (宿主外壳基座扩容后)由调用方在 `externals` 里给全量清单。
6
6
  */
7
7
  export declare const REACT_RUNTIME_MODULES: readonly string[];
8
8
  /**
9
- * 把注释行里的 pnpm 内容寻址段(store 目录里带「名@版_哈希」的那一层)折成普通的
9
+ * 把注释行里的 pnpm 内容寻址段(store 目录里带「名@版_哈希」的那一层)改写成普通的
10
10
  * `node_modules/` 一层。
11
11
  *
12
12
  * 为什么 client 侧需要而 host 侧不需要:host 把依赖全外部化,产物里没有依赖的模块标记;
13
13
  * client 必须把共享库的模块**内联**(浏览器解析不了裸说明符),于是 rolldown 写下的标记里
14
- * 烙着依赖版本与本机 store 哈希。带着它发布,同一份源码在不同机器上产出不同字节(跨机器
14
+ * 带着依赖版本与本机 store 哈希。带着它发布,同一份源码在不同机器上产出不同字节(跨机器
15
15
  * 不可复现),还把安装布局公开进公共 tarball。
16
16
  *
17
- * 两种注释形态都要折:workspace 软链安装下共享库模块标成 `//#region` 行;从 registry 安装时
17
+ * 两种注释形态都要改写:workspace 软链安装下共享库模块标成 `//#region` 行;从 registry 安装时
18
18
  * (消费仓 CI 的 frozen 安装正是这个形状)同一批模块标成 `// node_modules/…` 横幅,路径里带
19
- * `.pnpm/<名>@<版>_<peer 后缀>` 那一层。只折前者时,后者的 store 段原样留在产物里,下面的
20
- * 兜底判据把整次构建判红——0.1.8 就是在这个形状上红的,而伞内软链安装碰不到 `.pnpm`,
21
- * 所以本地检查与发布前的全量门都看不见它。
19
+ * `.pnpm/<名>@<版>_<peer 后缀>` 那一层。只改前者时,后者的 store 段原样留在产物里,下面的
20
+ * 兜底检查把整次构建判定失败——0.1.8 就是在这个形状上失败的,而工作区软链安装碰不到 `.pnpm`,
21
+ * 所以本地检查与发布前的全部检查都看不见它。
22
22
  *
23
- * 折叠必须覆盖整段而不是只换中段:store 段之上还可能带着 `../` 前缀(依赖落在工作区根
23
+ * 改写必须覆盖整段而不是只换中段:store 段之上还可能带着 `../` 前缀(依赖落在工作区根
24
24
  * 一侧时就是这样),只换中段会留下 `../../node_modules/<包名>/…`,产物字节仍然随检出
25
- * 深度变,等于没折。所以判据锚在行首、允许任意个相对段。
25
+ * 深度变,等于没改。所以匹配锚在行首、允许任意个相对段。
26
26
  *
27
27
  * 反斜杠先归一:Windows 上 rolldown 可能写 `\`,而这行是注释、整行只有路径,归一不会
28
- * 误伤代码。折叠完再验一遍「整份产物里不剩 `.pnpm` 段」——静默未命中是这条折法最坏的
29
- * 失效形态:判据锚在注释行的形状上,而 rolldown 一旦改写成别的行形态,折叠会一处都
30
- * 不命中,兜底若也跟着只用同一套形状假设,就会一起静默失明。`node_modules/.pnpm/`
28
+ * 误伤代码。改写完再验一遍「整份产物里不剩 `.pnpm` 段」——静默未命中是这条改法最坏的
29
+ * 失效形态:匹配锚在注释行的形状上,而 rolldown 一旦改写成别的行形态,改写会一处都
30
+ * 不命中,兜底检查若也跟着只用同一套形状假设,就会一起静默失效。`node_modules/.pnpm/`
31
31
  * 这个子串与行形态无关。
32
32
  * @param code - chunk 正文
33
- * @returns 折叠后的正文
33
+ * @returns 改写后的正文
34
34
  */
35
35
  export declare function collapseStorePaths(code: string): string;
36
36
  /**
37
37
  * 包名同源校验的上下文:校验逻辑在各包(它知道自己哪几个源文件带着包名字面量),
38
- * 判据材料在这里。
38
+ * 判断材料在这里。
39
39
  */
40
40
  export interface ClientNameContext {
41
- /** package.json 的 name(外壳 id 的真源)。 */
41
+ /** package.json 的 name(外壳 id 的唯一来源)。 */
42
42
  readonly pkgName: string;
43
- /** 折叠后的 chunk 正文(未包外壳)。 */
43
+ /** 改写后的 chunk 正文(未包外壳)。 */
44
44
  readonly body: string;
45
45
  /** 读包根下一份源码文件。 */
46
46
  readonly readSource: (relative: string) => Promise<string>;
@@ -59,22 +59,22 @@ export interface ClientBuildOptions {
59
59
  readonly externals?: readonly string[];
60
60
  /** 压缩产物。缺省不压。 */
61
61
  readonly minify?: boolean;
62
- /** 保留注释。缺省跟随 minify(压则剥,不压则留)。 */
62
+ /** 保留注释。缺省跟随 minify(压缩则移除,不压缩则保留)。 */
63
63
  readonly comments?: boolean;
64
64
  /** 包名同源校验。槽位 key、`$mount` 的 package 位之类各包自带的字面量声明在这里核对;
65
65
  * 缺省不校验。抛错即构建失败。 */
66
66
  readonly verifyName?: (context: ClientNameContext) => Promise<void> | void;
67
67
  }
68
68
  /**
69
- * 客户端外置判据:登记过的精确说明符外置,react 家族里**没登记**的说明符当场失败。
69
+ * 客户端外置规则:登记过的精确说明符外置,react 家族里**没登记**的说明符当场失败。
70
70
  *
71
71
  * 为什么既不静默内联也不前缀放行:外壳注入的 require 只在宿主模块表里查键。前缀放行会
72
72
  * 得到一条表里没有的 require(加载期 not in the module table,整张卡片静默不渲染);而
73
73
  * 静默内联会把 node_modules 里那份 React 打进产物、与宿主那份并存,页面里两个 React
74
74
  * 实例, hooks 直接报错。两种失败都不在构建期报错,所以这里没有可观察的中间态。
75
- * 导出给各包的构建脚本复用与测试直接驱动,与构建走同一份判据。
75
+ * 导出给各包的构建脚本复用与测试直接驱动,与构建走同一份判断。
76
76
  * @param externals - 外置说明符全量清单(精确匹配)
77
- * @returns rolldown 的 external 判据
77
+ * @returns rolldown 的 external 判定函数
78
78
  */
79
79
  export declare function clientExternalPredicate(externals: readonly string[]): (id: string) => boolean;
80
80
  /**
@@ -19,7 +19,7 @@ export interface HostBuildOptions {
19
19
  readonly entries: readonly HostEntry[];
20
20
  /** 压缩产物。缺省不压;装载器只 `import()` 文本,注释与空白是真实装载成本。 */
21
21
  readonly minify?: boolean;
22
- /** 保留注释。缺省跟随 minify(压则剥,不压则留)。 */
22
+ /** 保留注释。缺省跟随 minify(压缩则移除,不压缩则保留)。 */
23
23
  readonly comments?: boolean;
24
24
  /** rolldown 插件(如装饰器预转换)。缺省无。类型借 rolldown 自己的插件形状(仅类型导入)。 */
25
25
  readonly plugins?: RolldownPluginOption;
@@ -27,11 +27,11 @@ export interface HostBuildOptions {
27
27
  * 入口会导入 `.json` 数据的包要显式带上 `.json`。 */
28
28
  readonly resolveExtensions?: readonly string[];
29
29
  /** 是否外部化 optionalDependencies。缺省外部化:「装上就用、没装也能跑」的语义由
30
- * 运行期 require 决定,内联会把可选实现烤进产物、抹掉「可选」这层语义。
30
+ * 运行期 require 决定,内联会把可选实现固定进产物、抹掉「可选」这层语义。
31
31
  * 个别包刻意反向(可选依赖内联成「缺包时功能照旧」),传 false。 */
32
32
  readonly externalizeOptional?: boolean;
33
33
  }
34
- /** 一个 host 产物的构建结果。`inlinedModules` 是结构性外部化门禁的判据面。 */
34
+ /** 一个 host 产物的构建结果。`inlinedModules` 是结构性外部化检查的判断依据。 */
35
35
  export interface HostArtifact {
36
36
  readonly source: string;
37
37
  readonly output: string;
@@ -47,7 +47,7 @@ export interface HostArtifact {
47
47
  * 构建全部 host 入口。
48
48
  *
49
49
  * 各入口单独一次 rolldown 并发跑(它们互不依赖,串行只是在等第二次构建);产物正文
50
- * 先按 `process.cwd()` 无关的 canonical 形态正典化,再交给调用方落盘。
50
+ * 先按 `process.cwd()` 无关的 canonical 形态规范化,再交给调用方写入磁盘。
51
51
  * @param options - 见 {@link HostBuildOptions}
52
52
  * @returns 与入口表同序的产物清单
53
53
  */
@@ -25,7 +25,7 @@ export declare function canonicalizeDeclarationSpecifiers(text: string): string;
25
25
  *
26
26
  * `execFileSync` 不给 `encoding` 时两路都是 Buffer;按形态显式分支:文本原样用、Buffer
27
27
  * 按 UTF-8 解、其余形态返回空串。写成 `String(stream)` 会把 Buffer 送进默认字符串化,
28
- * 类型检查也会因为「可能是任意对象」而判红。
28
+ * 类型检查也会因为「可能是任意对象」而判定失败。
29
29
  * @param stream - 子进程的一路输出
30
30
  * @returns 文本
31
31
  */
@@ -34,7 +34,7 @@ export declare function textOf(stream: unknown): string;
34
34
  * 跑一条命令;失败时抛出的信息取子进程自己的诊断文本,而不是包装层的壳。
35
35
  *
36
36
  * 用同步版:这是构建步骤,阻塞等 tsc 跑完完全够用,异步包装在这里只会为了一个用不上
37
- * 的并发度引入回调与 Promise 两种形态。两路都得收:tsc 把编译诊断写 **stdout**,工具
37
+ * 的并发度引入回调与 Promise 两种形态。两路都得读:tsc 把编译诊断写 **stdout**,工具
38
38
  * 自身崩溃与 node 的用法错误写在 stderr,任取一路都会丢一半。
39
39
  * @param file - 可执行文件(用 `process.execPath` 跑入口 JS,不经 npx:Windows 上 `npx`
40
40
  * 实际是 `npx.cmd`,`execFileSync` 不带 `shell` 不按 PATHEXT 解析,一律 ENOENT)
@@ -46,8 +46,8 @@ export declare function runTool(file: string, args: readonly string[], cwd: stri
46
46
  * 递归列出目录下的声明文件(`/` 分隔,路径相对 `dir`)。
47
47
  *
48
48
  * 文件与目录分成两支再汇总:混在一个 map 里时,只有文件的那一支会变成一个没有 `await`
49
- * 的 `async` 回调;拆开后两支各自理由完整。导出而非私藏:调用方的声明门禁要按同一口径
50
- * 列 types/,在调用方重写一份遍历逻辑只会让两边的目录形状悄悄分叉。
49
+ * 的 `async` 回调;拆开后两支各自理由完整。导出而非私藏:调用方的声明检查要按同一规则
50
+ * 列 types/,在调用方重写一份遍历逻辑只会让两边的目录清单悄悄分叉。
51
51
  * @param dir - 当前目录绝对路径
52
52
  * @param prefix - 已走过的相对前缀(顶层调用传空串)
53
53
  * @returns 命中的文件清单
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 产物文本的 canonical 形态:所有 `//#region` 行折成与 process.cwd() 无关的形状,其余字节原样保留。
2
+ * 产物文本的 canonical 形态:所有 `//#region` 行改写成与 process.cwd() 无关的形态,其余字节原样保留。
3
3
  * @param code - builder 拿到的产物文本
4
4
  * @param pkgDir - 包根绝对路径(builder 的 import.meta.dirname)
5
5
  * @param cwd - 构建时的 process.cwd()。传入即走精确前缀档;省略走旧签名兼容档
@@ -1,32 +1,32 @@
1
1
  import type { Context } from "@deepseek-ai/cordis";
2
2
  /**
3
- * 客户端 apply 接收的 ctx 最小面。
3
+ * 客户端 apply 接收的 ctx 最小接口。
4
4
  * `effect` 逐字取官方 `Context['effect']`(installed
5
5
  * `@deepseek-ai/cordis/lib/types/fiber.d.ts`:`interface Context extends
6
6
  * Pick<Fiber, 'effect'>`,同步 `Disposable` 与可 await 的 `AsyncDisposable` 两条重载),
7
7
  * 而不是本地重述一条 `(factory: () => (() => void) | undefined, label?) => void`。
8
8
  * ⚠ 为什么这条要紧:各卡片的 `ClientCtx.effect` 绑的就是官方类型,而本地那份把 factory 的
9
9
  * 值域写**宽**了(官方 `SyncEffect` 不收 `undefined`)。函数属性位按 contravariance 检查,
10
- * 于是「官方 ctx」反而赋不进本投影——各卡片包会各自撞出一个
10
+ * 于是「官方 ctx」反而赋不进本投影——各卡片包会各自出现一个
11
11
  * `TS2345 … Type 'undefined' is not assignable to type 'SyncEffect<any>'`,
12
- * 并在每个消费包里用一个类型断言去过桥。守卫的 ctx 面归本模块所有,就在这里一次修好。
12
+ * 并在每个消费包里用一个类型断言绕过它。守卫的 ctx 类型归本模块所有,就在这里一次修好。
13
13
  */
14
14
  export interface CardApplyCtx {
15
15
  effect: Context["effect"];
16
16
  }
17
17
  /**
18
- * apply 幂等守卫:已 claim 返回 false(调用方直接 return),否则占位并
18
+ * apply 幂等保护:已 claim 返回 false(调用方直接 return),否则占位并
19
19
  * 挂 ctx.effect 清理——HMR 重载时 flag 复位,再次 apply 可重新声明。
20
20
  *
21
- * 占位值是本次 claim 现造的 symbol;守卫对外的判据面是「自有键上的 `true` 或任何 symbol」:
22
- * `true` 是外部可写的占位协议(判据放宽一分就重新打开 HMR 重复装载),symbol 品牌让
21
+ * 占位值是本次 claim 现造的 symbol;保护对外的判断标准是「自有键上的 `true` 或任何 symbol」:
22
+ * `true` 是外部可写的占位约定(判断放宽一分就重新打开 HMR 重复装载),symbol 标识让
23
23
  * 重复加载的另一份模块实例的占位同样被认出——两份实例各持各的 token,靠 typeof 而不是
24
- * 身份对上。清理只认**自己那枚** token:旧实例的 disposer 迟于新实例 claim 执行(HMR /
24
+ * 身份对上。清理只认**自己那个** token:旧实例的 disposer 迟于新实例 claim 执行(HMR /
25
25
  * 重复加载不保证时序,也不保证恰好调一次)时,它认不得新实例的占位,新 claim 得以保留;
26
26
  * claim 之前槽上已有的自有值按原样恢复,不抹成 undefined。
27
27
  *
28
- * ⚠ 标记是**进程级**的(同一枚 flag 在全页面只有一份),不是 per-ctx:同一张卡被第二个
29
- * ctx apply 时会被这一枚挡掉。要允许多 ctx 共存就得按 ctx 记账(WeakSet 一类),
28
+ * ⚠ 标记是**进程级**的(同一个 flag 在全页面只有一份),不是 per-ctx:同一张卡被第二个
29
+ * ctx apply 时会被这一个拒绝。要允许多 ctx 共存就得按 ctx 管理(WeakSet 一类),
30
30
  * 别改成这里"顺手放过第二次"——那会重新打开 HMR 重复装载这条路。
31
31
  * @param ctx - apply 的 ctx(需要 effect)。
32
32
  * @param flag - globalThis 上的占位标记键名(如 "__xxxCardApplied"),形态见 {@link isLegalClaimFlag}。
@@ -0,0 +1,33 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ /** 所有字段共享的文案与状态位。 */
3
+ export interface FieldBase {
4
+ label: string;
5
+ hint?: string;
6
+ detail?: string;
7
+ /** 设置键名,写到控件的 `data-field`(检查与测试的稳定锚点),不是 DOM id。 */
8
+ field?: string;
9
+ disabled?: boolean;
10
+ wide?: boolean;
11
+ compact?: boolean;
12
+ /** 控件的 DOM id;字段组件用 `useId` 生成,FieldLabel 用它建立 label↔control 关联。 */
13
+ controlId?: string;
14
+ }
15
+ /** 说明按钮与浮层:悬停/聚焦显示,点击钉住,Esc 关闭。 */
16
+ export declare function InfoTip(props: {
17
+ label: string;
18
+ detail: string;
19
+ /** 是否渲染可见字段名;FieldLabel 自己渲染标签时传 false,避免重复。 */
20
+ showLabel?: boolean;
21
+ compact?: boolean;
22
+ }): ReactElement;
23
+ /** 字段名 + 可选说明按钮。 */
24
+ export declare function FieldLabel(props: {
25
+ label: string;
26
+ detail?: string | undefined;
27
+ compact?: boolean | undefined;
28
+ controlId?: string | undefined;
29
+ }): ReactElement;
30
+ /** 行式字段的基础布局:左标签/提示,右控件。 */
31
+ export declare function Field(props: FieldBase & {
32
+ children?: ReactNode;
33
+ }): ReactElement;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 把一段完整说明拆成常显提示与浮层详情。
3
+ * 超过阈值的文案不进常显行,避免行内出现截断的省略号。
4
+ * @param text - 完整说明
5
+ * @param max - 常显阈值(字符数)
6
+ * @returns 常显提示或浮层详情
7
+ */
8
+ export declare function splitHint(text: string, max?: number): {
9
+ hint?: string;
10
+ detail?: string;
11
+ };
@@ -0,0 +1,33 @@
1
+ import type { ReactElement } from "react";
2
+ import type { FieldBase } from "./field.js";
3
+ /** 开关行。 */
4
+ export declare function ToggleField(props: FieldBase & {
5
+ checked: boolean;
6
+ onChange: (next: boolean) => void;
7
+ }): ReactElement;
8
+ /** 数字行:以显示单位读写,越界值不写入。 */
9
+ export declare function NumberField(props: FieldBase & {
10
+ value: number | undefined;
11
+ min?: number;
12
+ max?: number;
13
+ step?: number;
14
+ unit?: string;
15
+ placeholder?: string;
16
+ invalidHint: string;
17
+ onChange: (next: number | undefined) => void;
18
+ }): ReactElement;
19
+ /** 单行/多行文本。 */
20
+ export declare function TextField(props: FieldBase & {
21
+ value: string;
22
+ placeholder?: string;
23
+ multiline?: boolean;
24
+ monospace?: boolean;
25
+ onChange: (next: string) => void;
26
+ }): ReactElement;
27
+ /** 名单行:逗号或换行分隔。逗号形态不支持条目本身含逗号;自由文本与正则用 newline。 */
28
+ export declare function ListField(props: FieldBase & {
29
+ value: readonly string[];
30
+ separator?: "comma" | "newline";
31
+ placeholder?: string;
32
+ onChange: (next: string[]) => void;
33
+ }): ReactElement;
@@ -0,0 +1,19 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ /** 设置卡根容器:无外框、纵向排列。 */
3
+ export declare function CardForm(props: {
4
+ children?: ReactNode;
5
+ }): ReactElement;
6
+ /** 小节:分隔线 + 标题 + 可选说明。 */
7
+ export declare function Section(props: {
8
+ title: string;
9
+ hint?: string;
10
+ children?: ReactNode;
11
+ }): ReactElement;
12
+ /** 紧凑栅格:只用于工具开关这类重复布尔项。 */
13
+ export declare function FieldGrid(props: {
14
+ children?: ReactNode;
15
+ }): ReactElement;
16
+ /** 一行状态 chips,以 `·` 分隔。 */
17
+ export declare function StatusBar(props: {
18
+ items: readonly string[];
19
+ }): ReactElement | null;
@@ -0,0 +1,16 @@
1
+ import type { ReactElement } from "react";
2
+ /** 底部保存条:dirty 时吸底,显示条数与失败原因。 */
3
+ export declare function SaveBar(props: {
4
+ dirty: boolean;
5
+ busy: boolean;
6
+ writable: boolean;
7
+ error: string | null;
8
+ saveLabel: string;
9
+ savingLabel: string;
10
+ revertLabel: string;
11
+ dirtyLabel: string;
12
+ cleanLabel: string;
13
+ readOnlyLabel: string;
14
+ onSave: () => void;
15
+ onDiscard: () => void;
16
+ }): ReactElement;
@@ -0,0 +1,15 @@
1
+ import type { ReactElement } from "react";
2
+ import type { FieldBase } from "./field.js";
3
+ /** 一个候选项。`value` 必须在整份 options 里唯一:它同时是 React key 与选中判断依据。 */
4
+ export interface SelectOption {
5
+ value: string;
6
+ label: string;
7
+ disabled?: boolean;
8
+ group?: string;
9
+ }
10
+ /** 自定义下拉:浮层固定定位,键盘可选,点击外部关闭。 */
11
+ export declare function SelectField(props: FieldBase & {
12
+ value: string;
13
+ options: readonly SelectOption[];
14
+ onChange: (next: string) => void;
15
+ }): ReactElement;
@@ -0,0 +1,2 @@
1
+ /** 设置卡统一样式。颜色/圆角全部走宿主主题令牌。 */
2
+ export declare const CARD_UI_CSS = "\n.dsu-form{display:flex;flex-direction:column}\n.dsu-section{margin-top:24px;padding-top:24px;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-form>.dsu-section:first-child{margin-top:0;padding-top:0;border-top:0}\n.dsu-sectionTitle{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary)}\n.dsu-sectionHint{margin:4px 0 0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusbar{display:flex;flex-wrap:wrap;gap:4px 8px;margin-top:8px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-field{display:grid;grid-template-columns:minmax(0,1fr) minmax(240px,360px);column-gap:32px;align-items:center;padding:12px 0;border-top:.5px solid var(--dsw-alias-border-l2)}\n.dsu-fieldMeta{display:flex;flex-direction:column;gap:4px;min-width:0}\n.dsu-labelRow{display:flex;align-items:center;gap:6px;min-width:0}\n.dsu-label{font-size:13px;font-weight:500;line-height:1.5;color:var(--dsw-alias-label-primary)}\n.dsu-labelMono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}\n.dsu-hint{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-tertiary)}\n.dsu-control{min-width:0;display:flex;align-items:center;gap:8px}\n.dsu-fieldWide{grid-template-columns:minmax(0,1fr);align-items:start}\n.dsu-fieldWide .dsu-control{width:100%;max-width:720px;margin-top:2px}\n.dsu-help{display:inline-flex;align-items:center;gap:6px;min-width:0}\n.dsu-helpBtn{appearance:none;border:0;background:transparent;padding:0;width:16px;height:16px;display:inline-flex;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary);cursor:help;border-radius:50%;flex:none}\n.dsu-help:hover .dsu-helpBtn,.dsu-helpBtn:focus-visible{color:var(--dsw-alias-label-primary)}\n.dsu-helpBtn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-tip{position:fixed;z-index:60;box-sizing:border-box;max-width:min(340px,calc(100vw - 16px));max-height:calc(100vh - 16px);overflow:auto;overflow-wrap:anywhere;padding:10px 12px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);box-shadow:0 12px 32px rgb(0 0 0 / 45%);font-size:12px;line-height:1.6;font-weight:400;color:var(--dsw-alias-label-secondary)}\n.dsu-input{width:100%;height:34px;padding:0 12px;border:.5px solid var(--dsw-alias-border-l4);border-radius:var(--dsw-radius-md);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px}\n.dsu-input:focus-visible{outline:none;border-color:var(--dsw-alias-state-business-primary)}\n.dsu-input[aria-invalid=\"true\"]{border-color:var(--dsw-alias-state-error-primary)}\n.dsu-input:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}\n.dsu-input::placeholder{color:var(--dsw-alias-label-tertiary)}\n.dsu-textarea{height:auto;min-height:96px;padding:8px 12px;line-height:1.6;resize:vertical}\n.dsu-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}\n.dsu-numberWrap{display:flex;flex-direction:column;gap:4px;width:100%;min-width:0}\n.dsu-number{display:flex;align-items:center;gap:8px;min-width:0}\n.dsu-number .dsu-input{min-width:0}\n.dsu-unit{flex:none;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-error{margin:0;font-size:12px;line-height:1.5;color:var(--dsw-alias-state-error-primary)}\n.dsu-switch{appearance:none;width:36px;height:20px;border-radius:999px;border:0;padding:2px;background:var(--dsw-alias-border-l3);display:flex;align-items:center;cursor:pointer;flex:none;transition:background-color .16s}\n.dsu-knob{width:16px;height:16px;border-radius:50%;background:var(--dsw-alias-label-primary);transition:transform .16s,background-color .16s}\n.dsu-switch[aria-checked=\"true\"]{background:var(--dsw-alias-label-primary)}\n.dsu-switch[aria-checked=\"true\"] .dsu-knob{transform:translateX(16px);background:var(--dsw-alias-label-primary-foreground)}\n.dsu-switch:disabled{opacity:.4;cursor:not-allowed}\n.dsu-switch:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}\n.dsu-selectWrap{position:relative;width:100%;min-width:0}\n.dsu-select{display:flex;align-items:center;justify-content:space-between;gap:8px;text-align:left;cursor:pointer}\n.dsu-select[aria-expanded=\"true\"]{border-color:var(--dsw-alias-state-business-primary)}\n.dsu-selectValue{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.dsu-chevron{flex:none;color:var(--dsw-alias-label-tertiary);transition:transform .16s}\n.dsu-select[aria-expanded=\"true\"] .dsu-chevron{transform:rotate(180deg)}\n.dsu-menu{position:fixed;z-index:70;padding:4px;background:var(--dsw-alias-bg-layer-2);border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;box-shadow:0 12px 32px rgb(0 0 0 / 50%);max-height:280px;overflow:auto}\n.dsu-option{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.4;width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 10px;border-radius:8px;cursor:pointer;text-align:left}\n.dsu-option:hover,.dsu-option[data-active=\"true\"]{background:var(--dsw-alias-bg-layer-3)}\n.dsu-option:disabled{color:var(--dsw-alias-label-tertiary);cursor:not-allowed}\n.dsu-option:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}\n.dsu-optionGroup{padding:6px 10px 2px;font-size:11px;font-weight:600;color:var(--dsw-alias-label-tertiary)}\n.dsu-check{opacity:0;flex:none}\n.dsu-option[aria-selected=\"true\"] .dsu-check{opacity:1}\n.dsu-savebar{display:flex;align-items:center;gap:8px;padding:12px 0;margin-top:24px;border-top:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base)}\n.dsu-savebar[data-dirty=\"true\"]{position:sticky;bottom:0;z-index:2;box-shadow:0 -12px 24px rgb(0 0 0 / 35%)}\n.dsu-btn{appearance:none;border:.5px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:1.5;border-radius:var(--dsw-radius-md);padding:5px 14px;cursor:pointer;transition:background-color .12s,border-color .12s,color .12s,filter .12s}\n.dsu-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l3)}\n.dsu-btn:active:not(:disabled){background:var(--dsw-alias-bg-layer-1)}\n.dsu-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}\n.dsu-btn:disabled{opacity:.4;cursor:not-allowed}\n.dsu-btnPrimary{background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}\n.dsu-btnPrimary:hover:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.9)}\n.dsu-btnPrimary:active:not(:disabled){background:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);filter:brightness(.84)}\n.dsu-btnDanger{color:var(--dsw-alias-state-error-primary)}\n.dsu-btnDanger:hover:not(:disabled){color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2)}\n.dsu-status{margin-left:auto;font-size:12px;color:var(--dsw-alias-label-tertiary)}\n.dsu-statusError{color:var(--dsw-alias-state-error-primary)}\n.dsu-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:0 24px}\n.dsu-grid>.dsu-field{display:flex;flex-direction:column;align-items:stretch;gap:6px;padding:10px 0;border-top:.5px solid var(--dsw-alias-border-l1)}\n.dsu-grid>.dsu-field .dsu-control{width:100%}\n@media (max-width:640px){\n .dsu-field{grid-template-columns:minmax(0,1fr);align-items:start}\n .dsu-control{width:100%;max-width:720px}\n .dsu-section{margin-top:20px;padding-top:20px}\n}\n@media (prefers-reduced-motion:reduce){\n .dsu-switch,.dsu-knob,.dsu-chevron,.dsu-btn{transition:none}\n}\n";
@@ -0,0 +1,10 @@
1
+ /** 设置卡统一组件与样式。客户端专用的子模块,不进入根 barrel。 */
2
+ export { CARD_UI_CSS } from "./card-ui/styles.js";
3
+ export { splitHint } from "./card-ui/hint.js";
4
+ export { CardForm, FieldGrid, Section, StatusBar } from "./card-ui/layout.js";
5
+ export { Field, FieldLabel, InfoTip } from "./card-ui/field.js";
6
+ export type { FieldBase } from "./card-ui/field.js";
7
+ export { ListField, NumberField, TextField, ToggleField } from "./card-ui/inputs.js";
8
+ export { SelectField } from "./card-ui/select.js";
9
+ export type { SelectOption } from "./card-ui/select.js";
10
+ export { SaveBar } from "./card-ui/save-bar.js";