GitHub Desktop 自定义 ESLint 规则全解析:从规则目录到源码与测试实践 开发工具桌面应用【免费下载链接】desktopFork of GitHub Desktop to support various Linux distributions项目地址https://gitcode.com/gh_mirrors/des/desktop点击查看免费下载本篇技术指南围绕 GitHub Desktopdesktop/desktop仓库中 eslint-rules/README.md 展开系统讲解该项目自研 ESLint 规则的设计动机、目录结构、两类型规则体系、本地校验与测试方法并逐一剖析五个内置自定义规则insecure-random、react-proper-lifecycle-methods、react-no-unbound-dispatcher-props、react-readonly-props-and-state、no-loosely-typed-webcontents-ipc的源码实现与测试用例帮助你在自己的 TypeScript React Electron 项目中复刻这套「编译期拦截错误」的工程实践。为什么 GitHub Desktop 需要自定义 ESLint 规则GitHub Desktop 是一个以 TypeScript 为主、基于 React Electron 的桌面应用代码规模横跨 app/src渲染进程 UI与 app/src/main-process主进程。项目在 .eslintrc.yml 中同时启用了大量来自社区插件的规则但仍有几类问题「没有现成规则可覆盖」项目特有的架构约定例如 dispatcher 方法必须绑定this才能作为回调传递安全类问题例如使用Math.random()生成随机字节类型系统的语义约束例如 props/state 接口成员必须readonly、React 生命周期方法签名必须与类型参数一致Electron IPC 的强类型封装要求禁止直接调用松散类型的webContents.send。因此项目在根目录的eslint-rules/目录下自行编写规则并通过.eslintrc.yml在项目根部统一配置。所有自定义规则在 .eslintrc.yml 的CUSTOM区块中声明且全部以error级别启用意味着任何一处违规都会直接导致 lint 失败。仓库目录结构速览eslint-rules/ ├── README.md # 规则设计文档本文主题 ├── tsconfig.json # 规则自身的类型检查配置 ├── insecure-random.js # 规则 1禁止不安全的随机数来源 ├── no-loosely-typed-webcontents-ipc.js # 规则 2禁止松散类型的 webContents IPC ├── react-no-unbound-dispatcher-props.js # 规则 3禁止未绑定的 dispatcher 回调 ├── react-proper-lifecycle-methods.js # 规则 4React 生命周期方法签名校验 ├── react-readonly-props-and-state.js # 规则 5props/state 必须只读 └── tests/ ├── insecure-random.test.js ├── react-no-unbound-dispatcher-props.test.js ├── react-proper-lifecycle-methods.test.js └── react-readonly-props-and-state.test.js规则实现文件与对应测试文件一一对应除no-loosely-typed-webcontents-ipc外均有独立测试测试统一放在 eslint-rules/tests 目录下。新增一条规则前先查现有插件README 明确给出项目已在使用的插件清单新增规则前必须确认没有现成替代typescript-eslint/eslint-pluginpackage.json 中为^6.13.2eslint-plugin-babeleslint-plugin-jsdoc^43.0.1eslint-plugin-json^2.1.1eslint-plugin-prettier^3.1.4eslint-plugin-react^7.33.2以及 devDependencies 中的eslint-plugin-github^4.10.1。只有当这些插件无法覆盖需求时才把规则加入eslint-rules/并在 .eslintrc.yml 中注册。两种规则形态TS-aware 与纯 AST 规则README 将自定义规则划分为两类形态能力依赖项目示例TypeScript-aware 规则可检查 AST 及类型相关信息typescript-eslint解析器与typescript-estreereact-proper-lifecycle-methods常规 ESLint 规则仅需语法层面的 AST 检查标准 ESLint 规则 APIreact-no-unbound-dispatcher-props、insecure-random、react-readonly-props-and-state、no-loosely-typed-webcontents-ipc以react-proper-lifecycle-methods为例它通过typescript-eslint/typescript-estree提供的TSESTree类型定义如ClassDeclaration、MethodDefinition、Parameter来定位类的类型参数进而校验生命周期方法而react-no-unbound-dispatcher-props只对JSXExpressionContainer节点做正则匹配完全不需要类型信息。本地校验yarn check:eslint自定义规则代码带有// ts-check指令并尽可能添加 JSDoctype注解通过项目根目录的yarn check:eslint进行类型检查$ yarn check:eslint该脚本在 package.json 中定义为check:eslint: tsc -P eslint-rules/即用tsc按 eslint-rules/tsconfig.json 编译规则目录。该 tsconfig 的关键配置如下{ compilerOptions: { allowJs: true, checkJs: true, noEmit: true, target: ES2021, skipLibCheck: true, moduleResolution: node }, include: [*.js, test/*.js] }allowJscheckJs让tsc对纯 JS 规则文件做类型检查noEmit保证只检查不产出文件include覆盖规则本体与tests/下的测试文件。所有规则文件的头部都带有// ts-check并通过typedef {import(eslint).Rule.RuleModule} RuleModule之类的注解声明模块类型确保类型检查器能理解 ESLint 规则模块结构。本地测试yarn test:eslint测试文件与规则同放在eslint-rules/tests/从项目根目录执行$ yarn test:eslint对应脚本定义package.jsontest:eslint: jest eslint-rules/tests/*.test.js它直接调用 jest 运行eslint-rules/tests/*.test.js下的所有测试。每个测试套件通过RuleTester对规则注入「合法」与「非法」代码片段并断言非法片段应报出哪些消息 ID。用 VSCode 调试自定义规则README 提供了把调试任务加入.vscode/launch.json的配置{ command: yarn test:eslint, name: Test ESLint scripts, request: launch, type: node-terminal }将该对象追加到configurations数组后即可在 VSCode 中直接运行该任务调试器会附着到 jest 进程配合测试用例逐步单步执行规则代码。五个内置自定义规则逐一剖析1.insecure-random拦截不安全的随机数来源实现文件eslint-rules/insecure-random.js该规则基于 tslint-microsoft-contrib 的insecureRandomRule改编目的是杜绝使用非加密安全的随机数 API。它监听CallExpression命中以下两种情况即报错Math.random()—— 报mathRandomInsecure提示改用crypto.randomBytes()或window.crypto.getRandomValues()crypto.pseudoRandomBytes()或解构出的pseudoRandomBytes()—— 报pseudoRandomBytesInsecure提示改用crypto.randomBytes()。关键实现片段CallExpression(node) { const { callee } node if ( callee.type MemberExpression callee.object.type Identifier callee.object.name Math callee.property.type Identifier callee.property.name random ) { context.report({ node, messageId: mathRandomInsecure }) } // ...pseudoRandomBytes 分支同理 }测试 eslint-rules/tests/insecure-random.test.js 覆盖合法crypto.randomBytes()、window.crypto.getRandomValues()非法Math.random()、crypto.pseudoRandomBytes()、解构的pseudoRandomBytes()调用。2.react-no-unbound-dispatcher-props杜绝未绑定的 dispatcher 回调实现文件eslint-rules/react-no-unbound-dispatcher-props.js这是高度 GitHub Desktop 定制化的规则针对项目里「把 dispatcher 方法直接当回调传给组件」这一常见运行时错误。规则头注释给出了反例与正解// 反例resetSidebarWidth 被调用时 this 不是 dispatcher 实例运行时报错 Resizable onReset{this.props.dispatcher.resetSidebarWidth} / // 正解提取为绑定实例方法后再传入 private handleReset () { this.props.dispatcher.resetSidebarWidth } // ... Resizable onReset{this.handleReset} /实现上规则在JSXExpressionContainer节点中用正则^\{this\.props\.dispatcher\.检测 JSX 表达式是否直接引用 dispatcher 方法命中即报unboundMethodJSXExpressionContainer(node) { const text sourceCode.getText(node) if (/^\{this\.props\.dispatcher\./.test(text)) { const textWithoutContainer text.slice(1, text.length - 1) context.report({ node, messageId: unboundMethod, data: { text: textWithoutContainer } }) } }测试 eslint-rules/tests/react-no-unbound-dispatcher-props.test.js 中合法样本是箭头函数包裹的() { this.props.dispatcher.resetSidebarWidth }非法样本正是文档中的Resizable onReset{this.props.dispatcher.resetSidebarWidth} /并断言报出unboundMethod且text为this.props.dispatcher.resetSidebarWidth。3.react-readonly-props-and-state强制 props/state 接口只读实现文件eslint-rules/react-readonly-props-and-state.js该规则针对项目中「技术上可以改this.props但永远不该改」的事实强制所有以Props或State结尾的 TypeScript 接口成员声明为readonly。它监听TSInterfaceDeclarationTSInterfaceDeclaration(node) { if (node.id.name.endsWith(Props)) { ensureReadOnly(node.body) } if (node.id.name.endsWith(State)) { ensureReadOnly(node.body) } }ensureReadOnly对每个TSPropertySignature成员做两项检查未标记readonly时报signaturesShouldBeReadonly类型为Array...或...[]时报arraySignaturesShouldBeReadonly要求改用ReadonlyArray。注意该规则在create入口处对.ts文件直接返回空对象仅.tsx参与检查react-proper-lifecycle-methods也有同样的.ts跳过逻辑——这两个规则只面向 UI 组件文件。测试 eslint-rules/tests/react-readonly-props-and-state.test.js 验证readonly name: string合法name: string报signaturesShouldBeReadonlyArraystring与string[]均报arraySignaturesShouldBeReadonly不以 Props/State 结尾的接口如ISomeOtherThing不受影响。4.react-proper-lifecycle-methods校验 React 生命周期方法签名实现文件eslint-rules/react-proper-lifecycle-methods.js这是五个规则中最复杂的一个也是 README 明确列举的「TypeScript-aware 规则」代表。它针对 React 类组件的生命周期方法保证方法名、参数名、参数类型与组件声明的泛型类型参数一致。整体流程如下识别 React 组件extendsReactComponent(node)判断类的父类是React.Component或React.PureComponent提取类型参数getPropsType/getStateType从React.ComponentProps, State的superTypeParameters中解析出 props 与 state 类型名支持TSTypeReference如ICloningRepositoryProps空类型字面量{}亦被处理校验方法签名对以component或shouldComponent开头的方法逐一校验。各生命周期方法的期望参数如下表方法期望参数名称 类型componentWillMount/componentDidMount/componentWillUnmount无参数componentWillReceivePropsnextProps: PropscomponentWillUpdatenextProps: Props、nextState: StatecomponentDidUpdateprevProps: Props、prevState: StateshouldComponentUpdatenextProps: Props、nextState: State其他component*/shouldComponent*命名报reservedMethodName易与生命周期方法混淆禁止使用verifyParameters还允许「省略参数」——即少写参数不报错但多出的参数会报unknownParameter每个已声明参数依次通过verifyParameter做名称nameMismatch与类型typeMismatch双重校验。规则在 meta 中声明为fixable: code且schema: []不接收任何选项。测试 eslint-rules/tests/react-proper-lifecycle-methods.test.js 覆盖了完整的合法/非法矩阵例如shouldComponentUpdate(foo: string)报nameMismatch应为nextProps与typeMismatch应为ICloningRepositoryPropsshouldComponentUpdate(nextProps, foo)报第二个参数nameMismatch应为nextState多余参数additionalParam报unknownParametercomponentWillDoSomething、shouldComponentFoo这类以保留前缀命名的方法报reservedMethodName普通类非 React 组件中出现同名方法不报错。5.no-loosely-typed-webcontents-ipc强制使用强类型 IPC 封装实现文件eslint-rules/no-loosely-typed-webcontents-ipc.js该规则与 .eslintrc.yml 中针对electron的no-restricted-imports配置形成互补——后者禁止直接导入ipcRenderer/ipcMain要求改用项目自建的强类型封装前者则拦截渲染进程侧直接调用webContents相关方法。核心逻辑isLooselyTypesWebContentsCall监听CallExpression与OptionalCallExpression命中以下任意形态即报useStronglyTypedWebContentsIPCwc.send(...)标识符直接名为wcxxx.webContents?.send(...)或xxx.webContents.send(...)裸的webContents.send(...)。报错消息明确提示「请改用ipc-webcontents提供的强类型 IPC 辅助方法」与仓库中 app/src/main-process/ipc-webcontents.ts 的定位一致该规则无独立测试文件可参照其余四个规则的RuleTester模式补写。规则如何接入主 lint 流程自定义规则通过--rulesdir参数接入项目主 lint 命令package.json 中的定义eslint: eslint --cache --rulesdir ./eslint-rules \./eslint-rules/**/*.js\ \./script/**/*.ts{,x}\ \./app/{src,typings,test}/**/*.{j,t}s{,x}\ \./changelog.json\即eslint 以./eslint-rules为规则目录对规则自身、script/、app/源码与测试等路径执行检查。而 .eslintrc.yml 中的CUSTOM区块将这些规则统一配置为error配合root: true、typescript-eslint/parser与 prettier、github/react 等扩展构成完整约束体系。日常可通过yarn lint先跑 prettier 再跑lint:src或yarn lint:src直接触发检查。把这套实践移植到你的项目规则选择标准优先复用社区插件typescript-eslint、react、jsdoc、json、prettier、babel只有项目特有架构约定才自写规则两类规则按需选用需要类型信息如生命周期签名校验时使用typescript-eslint解析器与typescript-estree纯语法检查如 dispatcher 正则匹配用标准规则 API 即可类型检查保护规则本身给规则文件加// ts-check与 JSDoc 类型注解并配置独立的tsconfig.jsonallowJscheckJsnoEmit用tsc校验规则代码质量测试先行为每条规则配套RuleTester测试用「合法 非法」代码片段锁定行为再接入jest统一跑yarn test:eslint安全与强类型并重insecure-random与no-loosely-typed-webcontents-ipc提醒我们lint 规则不仅能管风格还能在编译期拦截安全风险和架构性误用是 Electron 这类长生命周期桌面应用值得借鉴的工程实践。赞分享开发工具桌面应用【免费下载链接】desktopFork of GitHub Desktop to support various Linux distributions项目地址https://gitcode.com/gh_mirrors/des/desktop点击查看免费下载相关推荐自定义 ESLint 规则GitHub Desktop 项目内规则开发实战指南自定义 ESLint 规则GitHub Desktop 项目内规则开发实战指南 GitHub Desktop仓库路径 desktop 是一个依赖大量插件规桌面应用版本控制开发工具CANN/ge ES接口普通输入样例使用指导样例使用指导 1、功能描述 本样例使用Relu算子普通输入进行构图旨在帮助构图开发者快速理解普通输入的定义和使用该类型算子进行构图 2、目录结构 angula人工智能深度学习模型编译模型优化编译器AscendGitHub Desktop 代码质量管控指南ESLint、Prettier 与自定义规则深度解析GitHub Desktop 代码质量管控指南ESLint、Prettier 与自定义规则深度解析 本文以 GitHub Desktopdesktop开源桌面应用版本控制开发工具上一篇推荐使用deoplete-jedi —— 快速、智能的Python代码补全神器下一篇32GB显存也能跑Qwen3-VL-32BComfyUI量化部署保姆级指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考