Joplin 编码规范实战:CLAUDE.md 指南、ESLint 自动化与源码级工程约定
Joplin 编码规范实战CLAUDE.md 指南、ESLint 自动化与源码级工程约定【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplinJoplin 仓库根目录的CLAUDE.md是一份面向 AI 编码助手与人类贡献者的简明工程守则Joplin Guidelines它把项目最核心的代码风格、测试、样式与工具链约定浓缩为一个“快速参考”。本篇以该文档为骨架逐条解读其规则并结合仓库中的eslint配置、pre-commit 钩子、cspell拼写检查与 coding_style.md 等配套文档说明每条规则背后的自动化支撑与源码级落地方式帮助你在提交任何修改前做到与项目惯例完全一致。快速参考Quick Reference总览CLAUDE.md 的第一部分列出了 18 条高频规则覆盖格式、类型、注释、测试、工具链与文档六大方面。下面按主题分组逐条展开。格式与 TypeScript 类型制表符缩进整个仓库统一使用 Tab 缩进而非空格。字符串使用单引号与多数 JS 项目偏好双引号不同Joplin 规定字符串一律使用单引号。使用规范的 TypeScript 类型避免any这是硬性要求any会绕过类型检查削弱整个 monorepo 的类型安全。不要标注可推断的类型当 TypeScript 能从上下文推断出类型时例如const x foo推断为string不要显式写出返回类型或const类型只有在 TS 会推断出any时才需要显式标注。这一点与 coding_style.md 中“Dont set the type when it can be inferred”一节完全对应后者指出 ESLint 的no-inferable-types规则只覆盖简单类型函数调用等场景仍需自觉避免冗余标注。Markdown 文件不要硬换行段落内不手动折行交给渲染器自动换行只有在真正的段落或列表分隔处才插入换行符。注释与代码复用注释只用//不要写 JSDoc 语法项目不采用/** ... */块注释风格。默认不写注释仅在“为什么这样做”不明显时才加注释例如 workaround、隐藏约束、微妙不变量且尽量控制在一两行永远不要解释代码“做了什么”——变量名和函数名已经承担了这一职责。复制大段代码时必须声明如果你复制了一块可观的代码需在复制处上方加注释注明这是重复代码并给出原始位置的文件/路径引用以便日后同步维护。Jest 测试约定每个测试文件只允许一个顶层describe()保持文件结构单一便于浏览与定位。聚焦核心行为与边界情况不要为每个细枝末节添加琐碎测试测试应覆盖关键行为与 edge case。避免测试中的重复代码当同一逻辑用不同输入测试时使用test.each或共享 helper而不是复制相似的测试块。这与 coding_style.md 的“Test units”一节互为补充该项目还主张避免 mock 对象与 spy——优先测试真实输入输出例如真实写临时文件、真实建库写行只在别无选择时才使用jest.spyOn/mockImplementation因为过度打桩实际上是在测“假实现”。工具链与架构约束新增 TypeScript 文件后运行yarn updateIgnored在仓库根目录执行这条规则背后是一个自动生成机制下文“自动化落地”一节会展开。遇到 cSpell 未知单词时按 readme/dev/spellcheck.md 的规定处理加入词表或使用cSpell:disable注释块详见后文。编译 TypeScript 使用yarn tsc只做类型检查不产出文件时用yarn tsc --noEmitpackage.json 中tsc脚本实际是yarn workspaces foreach --worktree --parallel --verbose --interlaced run tsc即按 workspace 并行分发到各个packages/*子包中执行各自的tsc这与项目的 monorepo 结构workspaces: [packages/*]一致。SQL 查询只允许出现在 models 中packages/lib/models目录这是 Joplin 的核心架构约束——packages/lib是可被 CLI、桌面端Electron、移动端React Native三端共用的数据层所有数据访问必须收敛到packages/lib/models/下的模型类如BaseItem.ts、Note.ts等禁止在 service、命令或其他任意位置直接拼接 SQL从而保证三端数据库驱动SQLite / better-sqlite / 移动端存储下的行为一致。桌面端样式规范StylingCLAUDE.md 的“Styling (desktop app)”一节规定桌面端只使用 RSCSS SCSS 文件组织样式禁止内联style{{...}}和 styled-components例外内联style只用于“真正的逐实例动态值”例如计算出来的宽度、坐标位置主题色一律使用var(--joplin-*)CSS 变量而不是在 JS 中读取主题对象再传颜色值。这些规则的完整依据在 readme/dev/spec/desktop_styling.md。该文档交代了桌面端样式方案的三次演进直接内联 style缺乏灵活性、无法被自定义样式表覆盖→ styled-components需要为每种样式建组件、且存在若干样式失效的 bug→当前的 SCSS 普通 CSS 类。工程上应用样式表由构建packages/app-desktop/style.scss生成新建组件时应同时新建一个样式文件如MyComponent/style.scss并在根style.scss中引入全局样式放根 main.scss每次构建会把style.scss编译为最终的style.css打进应用。类名组织遵循RSCSS 约定需要记住的要点组件类名至少两个词如.search-form组件内元素类名只用一个词如.field、textinput始终使用子代选择器防止样式在嵌套组件间“渗透”。例如form classorder-form input classfirstname typetext/ div classslider-box Select quantity: div classknob/div /div /form.order-form firstname, .order-form lastname { padding: 10px; }若某个元素如slider-box既是独立组件又是父组件的子元素不要写.order-form .slider-box而是给它额外命名如quantityslider后选择.order-form .quantityslider目标是“精准命中标定的元素不多不少”。自动化落地pre-commit 钩子、lint-staged 与 cSpellCLAUDE.md 末尾指向 readme/dev/coding_style.md其开篇说明了这些规范的执行机制编码风格主要由运行eslint的 pre-commit 钩子强制该钩子在任一应用目录执行yarn install时自动安装若钩子缺失在仓库根目录重新执行yarn install即可恢复。仓库中可验证的对应物.husky/pre-commit 的内容只有一行corepack yarn lint-staged即提交前对暂存文件运行 lint-staged根目录 lint-staged.config.js 定义了对待提交文件执行检查的具体命令package.json 的postinstall脚本为husky gulp build解释了“yarn install之后钩子即生效”的原因手动运行 lint 的方式为yarn linter ./即eslint --fix --quietCI 使用yarn linter-cieslint --quiet不带--fix保证失败即报红。coding_style.md 还给出了新增 ESLint 规则的标准流程把规则加进 ESLint 配置后老代码往往会大面积报错此时二选一——文件不多且改动简单就直接逐一修复首选或者运行yarn linter-interactive ./交互式为存量违规行逐条添加eslint-disable-next-line注释并统一标注 “Old code before rule was applied” 以便日后检索。这样存量代码保持不动、新代码强制遵守规则。yarn updateIgnored背后的生成机制CLAUDE.md 要求“新增.ts文件后运行yarn updateIgnored”其实现是 packages/tools/gulp/tasks/updateIgnoredTypeScriptBuild.js以 glob 扫描全仓库的**/*.ts与**/*.tsx排除node_modules、各包构建产物、测试夹具、packages/server、packages/utils等目录并过滤掉.d.ts为每个.ts文件推导对应编译产物.js的文件名用正则定位.gitignore与.ignore.eslint中由# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD标记的自动生成分区把最新列表整块替换进去。原理是TypeScript 编译会产出.js文件这些本地产物既不能进版本库也不能参与 lint所以每次源码文件增删后都要重新生成这两处忽略清单——yarn updateIgnored对应node packages/tools/gulp/tasks/updateIgnoredTypeScriptBuildRun.js就是把这一机械步骤自动化。拼写检查cSpellCLAUDE.md 引用了 readme/dev/spellcheck.md仓库中的 Markdown 与 TypeScript 文件会被 cspell.json 配置的 CSpell 自动检查。实操要点全量检查yarn spellcheck --all单文件yarn spellcheck /path/to/filepre-commit 钩子会自动检查新提交文件中的拼写忽略词两种途径追加到packages/tools/cspell/下的词表文件每个词表不超过约 400 词超出会导致 CSpell 加载失败需另建词表并在cspell.json中注册或对含大量不可忽略词的代码块使用// cSpell:disable/// cSpell:enableMarkdown 中为!-- cSpell:disable --更推荐优先用词表以免污染代码也可在cspell.json中用ignore属性按路径或正则整体跳过例如忽略 changelog 中的 GitHub 用户名。深入配套文档coding_style.md 的关键细则CLAUDE.md 的快速参考是“摘要层”readme/dev/coding_style.md 是“细则层”两者必须结合阅读。以下几组细则对实际写代码影响最大。文件命名与导入导出多个东西的文件用camelCase.ts仅当文件包含单一类且为默认导出时才用PascalCase.ts共享类型定义放types.ts或fooTypes.ts导出成员与导入成员保持相同的命名大小写文件、函数、导入名一致只导入需要的成员利于 tree shakingimport { writeFile } from fs-extra优于import * as fsTypeScript 文件中优先import而非require以便享受类型检查老包没有类型声明时才退回require()避免内联类型类型应单独定义以便复用type Config Recordstring, Knex.Config; const config: Config { /* ... */ };变量与函数新代码中的常量用camelCase不用全大写SNAKE_CASE变量声明尽量贴近其首次使用处避免“声明在最顶部却隔了很远才用”优先const而非let优先箭头函数() {}而非function() {}——不用this便于日后把类组件重构为 React Hooks且对this的误用会被 TypeScript 直接报错尽量避免默认参数与可选字段所有参数都必填时重构代码编译器会自动帮你发现漏传。安全转义用户内容Escape variables这是细则文档中篇幅最大的安全章节核心原则永远不要假设输入安全即使你认为自己控制了输入且尽可能晚地转义——应用内部保持原始数据只在边界处解码/编码避免双重转义。按插入位置选择手段插入位置手段JS 脚本字符串JSON.stringify(data)HTML 字符串htmlentities来自 packages/utils/html.ts如htmlentities(content)URL 查询参数encodeURIComponent完整 URL 用encodeURIMarkdownpackages/lib/markdownUtils.ts 提供escapeTableCell()、escapeInlineCode()、escapeTitleText()、escapeLinkUrl()文档还提出了“Make wrong code look wrong”命名法给已转义变量加后缀如userContentHtml让“把未转义变量插进 HTML”这件事在代码审阅中一眼可见、一眼可疑。数据库约定表名与列名一律snake_case所有列NOT NULL可带默认值避免查询中同时处理NULL/0/ 空串默认值要克制——多数情况应要求调用方显式传值枚举值用 integer 列 TypeScript enum表达不用数据库内置 enum迁移困难布尔语义优先tinyint(1)而非boolSQLite/MySQL 中布尔本就不是独立类型。React 与 GitHub Actions新组件一律函数组件 Hooks不写extends Component类组件长逻辑抽成自定义 hook注意 hook 必须以use开头否则 eslint 会报 “called outside of a component”GitHub Actions 的run块内不要内嵌${{ }}存在脚本注入风险应通过env传入后再引用环境变量。文档引用与延伸阅读CLAUDE.md 末尾的“Full Documentation”给出了两个权威入口编码风格全文readme/dev/coding_style.md本文已大量引用贡献指南CONTRIBUTING 文件其内容指向 readme/dev/index.md 这一开发者指南总入口该目录下还有构建BUILD.md、部署DEPLOY.md、技术规格technical_spec.md、本地化、构建排错 以及 readme/dev/spec/ 下数十篇子系统规格文档同步、服务器、编辑器、插件等。适用前提小结本文所述约定均以当前仓库实际内容为准Node 引擎要求22.12、Yarn 版本锁定engines 声明4.12.0packageManager声明yarn4.16.0见 package.json。如果你要在 Joplin 仓库内提交代码最短执行路径是写完代码后先跑yarn tsc --noEmit做类型检查、yarn linter ./修风格问题、新增.ts文件后执行yarn updateIgnored、遇到拼写告警按 readme/dev/spellcheck.md 处理词表——pre-commit 钩子会在提交时兜底拦截不符合 CLAUDE.md 约定与 ESLint 规则的代码。【免费下载链接】joplinJoplin - the privacy-focused note taking app with sync capabilities for Windows, macOS, Linux, Android and iOS.项目地址: https://gitcode.com/GitHub_Trending/jo/joplin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

最新新闻

日新闻

周新闻

月新闻