2026/9/13 10:43:23

Appium 用 @appium/oxc-config 统一 Oxlint 与 Oxfmt 配置:共享 Lint/格式体系的实现与实践

Appium 用 @appium/oxc-config 统一 Oxlint 与 Oxfmt 配置:共享 Lint/格式体系的实现与实践 Appium 用 appium/oxc-config 统一 Oxlint 与 Oxfmt 配置共享 Lint/格式体系的实现与实践【免费下载链接】appiumCross-platform automation framework for all kinds of apps, built on top of the W3C WebDriver protocol项目地址: https://gitcode.com/GitHub_Trending/ap/appiumappium/oxc-config是 Appium monorepo 抽出的共享代码风格包它把 Appium 项目沉淀多年的 Oxlint 规则集和 Oxfmt 格式选项固化成两个可import的 ES Module 子路径并锁定与之兼容的oxlint、oxlint-tsgolint、oxfmt版本。读完本文你可以掌握如何在自己的 Appium 周边项目中接入这套共享配置、理解其中 type-aware 规则、.editorconfig回退合并等关键机制以及这套配置是如何替代旧 ESLint 共享配置的。包定位从 ESLint 共享配置迁移到 Oxc 工具链appium/oxc-config诞生于 Appium 将代码质量工具链从 ESLint 迁移到 Oxc 生态的演进过程中。旧包appium/eslint-config-appium-ts的文档已明确标记Deprecated并指引项目迁移到appium/oxc-config。从 oxlint.mjs 的头部注释可以看到该配置是 Migrated from appium/eslint-config-appium-ts via oxlint/migrate即通过官方迁移工具自动转换而来同时有意剥离了所有样式类stylistic规则——这些职责交由 Oxfmt 承担。包的关键元信息见 packages/oxc-config/package.json版本锁定dependencies中以精确版本钉住三个二进制工具——oxlint 1.80.0、oxfmt 0.65.0、oxlint-tsgolint 7.0.2001。这意味着使用者npm install appium/oxc-config后npx oxlint/npx oxfmt调用的就是与共享配置规则语法完全兼容的版本避免配置写了新版才有的规则、本地却是旧版二进制的错配问题。子路径导出exports字段仅暴露两个入口——./oxlint指向oxlint.mjs./oxfmt指向oxfmt.mjs与下文用法一一对应。运行环境engines要求node ^20.19.0 || ^22.12.0 || 24.0.0、npm 10与 monorepo 根 package.json 的 engines 约束一致。变更记录packages/oxc-config/CHANGELOG.md 显示该包在 1.1.02026-07-25以 Add centralised Oxc lint and format config 引入核心能力。安装与快速接入安装npm install appium/oxc-config --save-devOxlint 接入在项目根目录创建oxlint.config.mjs从子路径导入共享配置import appiumConfig, {defineConfig, ignorePatterns} from appium/oxc-config/oxlint; export default defineConfig({ extends: [appiumConfig], ignorePatterns: [...ignorePatterns], });运行检查npx oxlint -c oxlint.config.mjs .Oxfmt 接入在项目根目录创建oxfmt.config.mjsimport appiumConfig, {defineConfig, ignorePatterns as appiumIgnorePatterns} from appium/oxc-config/oxfmt; export default defineConfig({ ...appiumConfig, ignorePatterns: [...appiumIgnorePatterns], });运行格式化npx oxfmt -c oxfmt.config.mjs .注意两处导入的不对称设计Oxlint 走extends合并、而 Oxfmt 走展开spread合并且两者的ignorePatterns都必须显式导入再展开。这是由工具本身的行为决定的下面两节会分别展开。深入 Oxlint 共享配置oxlint.mjsoxlint.mjs 导出三样东西默认导出的配置对象、从oxlint包再导出的defineConfig以及具名导出的ignorePatterns。逐项拆解其内容。ignorePatterns为何必须手动展开export const ignorePatterns [**/.*, **/*-d.ts, **/build/**, **/coverage/**, **/build-fixtures/**];源码注释明确说明Oxlint does not inheritignorePatternsviaextends。也就是说extends: [appiumConfig]会继承 rules/overrides但不会继承 ignore 列表因此官方用法要求你在自己的根配置里把数组导入并展开。同时 Oxlint 会自动尊重.gitignore无需重复列举。全局选项关闭 correctness 类别 开启类型感知categories: { correctness: off, }, options: { typeAware: true, }, env: { builtin: true, },typeAware: true通过捆绑的oxlint-tsgolint依赖启用类型感知type-aware规则——这正是需要锁定oxlint-tsgolint版本的原因类型感知能力由该插件提供配置中大量typescript/*规则依赖它才能完整生效。correctness: off关闭了 Oxlint 默认的 correctness 类别兜底转而用下方逐条列出的规则做精细控制行为可预期、可迁移。规则分组从 ESLint 插件体系平移而来rules字段按来源分组、注释清晰共约 90 条规则主要五组ESLint recommendedjs/recommended如no-undef: error、no-unused-vars: warn、no-fallthrough: error、no-prototype-builtins: warn并保留了两处显式放宽no-empty: off、no-unexpected-multiline: off与旧 ESLint 配置的行为对齐。eslint-plugin-promisepromise/always-return: error、promise/no-new-statics: error其余如promise/catch-or-return、promise/prefer-await-to-callbacks等设为warnpromise/avoid-new显式off。eslint-plugin-import-ximport/namespace: error、import/no-duplicates: error等模块解析类规则。typescript-eslint recommended类型感知规则集中区例如typescript/consistent-type-imports强制prefer: type-importsfixStyle: separate-type-imports即import type必须单独成行typescript/no-namespace、typescript/no-this-alias为errortypescript/no-non-null-assertion: warn允许在业务代码中受控使用!。Appium 自定义规则curly: error必须写大括号、no-console: error禁止 consoleAppium 有统一的 logger 体系、eqeqeq: [error, smart]、object-shorthand: error、unicorn/prefer-node-protocol: warnimport node:fs风格建议。overrides按文件类型和测试目录分级overrides: [ { files: [**/*.{js,mjs,cjs,jsx,mjsx,ts,tsx,mtsx}], plugins: [promise, import, typescript, unicorn], env: {es2022: true, node: true}, globals: {NodeJS: readonly, BufferEncoding: readonly}, }, { files: [**/*.{ts,tsx,mtsx}], plugins: [typescript], rules: { typescript/no-floating-promises: warn, }, }, { files: [**/test/**], plugins: [typescript, import], rules: { no-unused-expressions: off, import/no-named-as-default-member: off, typescript/ban-ts-comment: off, typescript/no-non-null-assertion: off, typescript/no-floating-promises: off, }, }, ],三段 overrides 体现了测试代码更宽松的惯例测试目录**/test/**关闭了no-unused-expressions断言中常见expect(x).to.be.ok这类表达式、ban-ts-comment和no-floating-promises等。冒烟测试 scripts/test-smoke.mjs 第一行就断言appiumOxlintConfig?.overrides?.length必须存在说明这套 override 结构是配置正确性的组成部分。深入 Oxfmt 共享配置oxfmt.mjsoxfmt.mjs 是包内技术含量最高的文件它解决了一个实际问题Appium 的缩进、换行等格式参数由仓库根的 .editorconfig 统一约定而 Oxfmt 本身也原生读取.editorconfig——如果共享配置硬编码这些值就会覆盖用户在子目录用.editorconfigglob 覆盖的格式。固定格式选项createFormatOptions()始终返回一组与.editorconfig无关的选项{ semi: true, singleQuote: true, quoteProps: as-needed, trailingComma: all, bracketSpacing: false, sortImports: true, ...resolveEditorConfigFallbacks(cwd), }即语句分号、单引号、按需引号属性、全尾逗号、紧贴花括号{foo}而非{ foo }、自动排序 import。这些就是 Appium 源码风格的直接体现。.editorconfig 回退合并机制editorConfigFallbacks镜像了 monorepo 根 .editorconfig 的内容printWidth: 120、tabWidth: 2、useTabs: false、endOfLine: lf、insertFinalNewline: true并维护一张 Oxfmt 键到 editorconfig 键的映射表Oxfmt 选项.editorconfig 属性printWidthmax_line_lengthtabWidthindent_sizeuseTabsindent_styleendOfLineend_of_lineinsertFinalNewlineinsert_final_newline核心逻辑分三步见 oxfmt.mjs 中对应函数findEditorConfig(cwd)从当前目录逐级向上查找最近的.editorconfig找不到返回nullparseEditorConfigDefinedKeys()解析该文件中所有已定义的属性名忽略注释行与 section 头得到用户已显式声明的集合resolveEditorConfigFallbacks(cwd)逐选项判断只有.editorconfig未定义该属性时才填入 Appium 回退值已定义的属性保持 unset让 Oxfmt 在格式化时按.editorconfig的 section/glob 覆盖生效。这个逐属性而非整文件的粒度是关键设计例如某子目录.editorconfig只写了indent_size那么tabWidth交给该文件而printWidth、endOfLine等仍取 Appium 回退值。Oxfmt 的 ignorePatternsOxfmt 的忽略列表比 Oxlint 更宽额外排除了会被误格式化的产物与文档export const ignorePatterns [ **/.*, **/build/**, **/fixtures/**, **/*.min.*, **/*.md, **/*.html, **/generated/**, **/*.hbs, **/*mkdocs.{yml,yaml}, ];值得注意的是它忽略**/*.md、**/*.html和 mkdocs 配置——这些正是文档站mkdocs 站点的产物不应被格式化。monorepo 内的真实用法Appium 仓库根目录本身就在使用这套包是最权威的接入范例。根 oxlint.config.mjsimport appiumConfig, {defineConfig, ignorePatterns as appiumIgnorePatterns} from appium/oxc-config/oxlint; export default defineConfig({ extends: [appiumConfig], ignorePatterns: [ ...appiumIgnorePatterns, packages/appium/docs/**/assets/**, packages/appium/docs/**/js/**, packages/appium/sample-code/**, ], });根 oxfmt.config.mjs 同构额外忽略了packages/appium/docs/**以及两个生成产物 appium-config.schema.json 与 appium-config.ts。这展示了本地扩展模式先展开共享 ignorePatterns再追加项目自己的忽略项。根 package.json 的 scripts 把工具命令固化下来日常开发与 CI 分别走npm run lint # oxlint -c oxlint.config.mjs . npm run lint:ci # oxlint -c oxlint.config.mjs --quiet . npm run lint:fix # oxlint -c oxlint.config.mjs --fix . npm run format # oxfmt -c oxfmt.config.mjs . npm run format:check # oxfmt -c oxfmt.config.mjs --check .其中lint:ci用--quiet只报告 error 级别format:check只做检查不落盘适合提交前校验。另外注意 monorepo 根的 eslint.config.mjs 仍在运行旧 ESLint 配置两者当前并存——从源码结构看仓库正处于 ESLint → Oxlint 的过渡期新代码风格请以oxc-config为准。冒烟测试如何守护这份配置scripts/test-smoke.mjs 通过npm run test:smoke对应 monorepo 根test:smoke→lerna run test:smoke运行对配置本身做结构断言覆盖三类契约导出契约defineConfig必须是函数两个子路径都要、overrides与两份ignorePatterns必须非空、singleQuote必须为真、editorConfigFallbacks.printWidth必须为 120 且endOfLine为lf无 .editorconfig 场景对临时目录os.tmpdir()调createFormatOptions()断言回退值生效printWidth 120有 .editorconfig 场景对 monorepo 根断言printWidth/tabWidth保持 unset因根.editorconfig已定义并动态构造一个只写了indent_size 2的部分.editorconfig临时目录验证tabWidth交给该文件、printWidth/endOfLine仍取 Appium 回退——正是前述逐属性回退机制的行为测试。这意味着上游改动共享配置后只需跑一次冒烟测试即可确认格式契约没有被破坏。遗留 ESLint 规则对照表README 中Rules without Oxlint equivalents一张表说明哪些旧规则在 Oxlint 中尚无对应实现接入时不要指望这些约束自动生效Legacy ruleNotestypescript-eslint/member-orderingClass member orderingn/no-deprecated-apiNode.js deprecated API usagejsdoc/require-jsdocJSDoc on exported functionsperfectionist/sort-modulesExport-before-non-export module orderingstylistic/*Replaced by Oxfmt其中最后一行的处理方式值得注意样式类规则stylistic/*由 Oxfmt 完整接管这正是lint 只管语义正确性、fmt 只管排版的职责切分。适用前提与限制版本前提包内锁定oxlint 1.80.0、oxfmt 0.65.0、oxlint-tsgolint 7.0.2001若你的项目已有其他来源的同名依赖注意npx解析到的版本应与共享配置匹配否则 type-aware 规则可能失效。环境前提Node^20.19.0 || ^22.12.0 || 24.0.0、npm10。行为边界.editorconfig只在 Oxfmt 侧参与回退合并Oxlint 不消费它两个工具的 ignore 列表不同Oxlint 5 条、Oxfmt 9 条扩展时不要互相照抄。迁移残留member-ordering、Node deprecated API 检查、JSDoc 强制、模块内 export 排序这四项约束目前无任何工具执行属于已知缺口。小结appium/oxc-config用两个轻量 ES Module 把 Appium 的代码风格约束产品化了oxlint.mjs 提供约 90 条按来源分组、带三段 overrides 的规则集和 type-aware 能力oxfmt.mjs 提供固定排版选项加一套逐属性感知的.editorconfig回退合并逻辑配合版本锁定与冒烟测试守护配置契约。对外部 Appium 生态项目driver、plugin而言按本文快速接入两节复制两个配置文件即可与 Appium 官方仓库保持完全一致的 lint 与格式行为对仓库维护者而言改动风格约束时应同步更新共享包并跑通test:smoke。【免费下载链接】appiumCross-platform automation framework for all kinds of apps, built on top of the W3C WebDriver protocol项目地址: https://gitcode.com/GitHub_Trending/ap/appium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考