【eslint 插件】导入语句排序

编写思路

  • 通过编写 eslint 插件
  • 在 ast 遍历过程中筛选出所有导入语句
  • 记录排序前导入语句代码块内容
  • 对导入语句进行排序
  • 比对排序前后导入语句代码块
  • 若不一样则进行替换

排序规则

  • 对导入语句进行分组
    • npm 包
    • 相对路径/绝对路径
      • 判断路径中是否携带指定路径类型(ex.['components', 'api']),若携带则划分至该路径类型组
      • ex. import aa from './../seller/components/aa',划分至 components 组
      • 若不携带,则正向遍历找到第一个路径,划分至该路径分组
      • ex. import aa from './../hooks/aa',划分至 hooks 组
      • 若存在分组内仅有一条导入语句,划分至合并分组
    • import type
  • 属性排序
    • 针对具名导入,属性由短至长排序
  • 组内排序
    • 导入语句由短至长排序
  • 组间排序
    • npm 包最前,合并分组 & 类型导入分组位于最后
    • 其余分组按照导入语句数量由短至长排序
    • 组间空一行

插件使用

arduino 复制代码
pnpm add eslint-plugin-for-sort-import -D
js 复制代码
// eslint.config.js
import importSortPlugin from 'eslint-plugin-for-sort-import'

export default [
  ...importSortPlugin(),
]

若未生效可重启编辑器 or

bash 复制代码
ctrl + shift + p,输入 restart eslint server

参数说明

csharp 复制代码
export interface PluginConfig {
  /** 行尾风格: 'lf' 或 'crlf' */
  end_of_line: 'lf' | 'crlf'
  /** 缓存大小限制 */
  max_cache_size: number
  /** 路径类型识别列表 */
  path_type: string[]
}
  • end_of_line: 行尾风格,默认 'lf'
    • 用于决定换行符采用 '\n' 还是 '\r\n'
  • max_cache_size: 缓存大小限制
    • 插件采用了 LRU Cache,缓存文件排序后的结果
  • path_type: 路径类型识别列表
    • 用于指定分组

核心逻辑

此处仅展示了最简单的将导入语句按照长短排序

js 复制代码
export const sortImportsRule = {
  meta: {
    type: 'suggestion',
    docs: {
      description: '导入语句按照指定规则排序',
      category: 'Stylistic Issues',
      recommended: false
    },
    fixable: 'code'
  },
  create(context) {
    return {
      Program(node) {
        const sourceCode = context.getSourceCode()

        // 筛选出所有导入声明
        const importDeclarations = node.body.filter((node) => node.type === 'ImportDeclaration')
        if (importDeclarations.length === 0) return

        // 获取当前导入代码块
        const start = importDeclarations[0].range[0]
        const end = importDeclarations[importDeclarations.length - 1].range[1]
        const currentText = sourceCode.text.slice(start, end)

        // 生成排序后的导入代码块
        const group = [...importDeclarations]
        group.forEach((node, index) => {
          group[index].processedText = sourceCode.getText(node)
        }
        group.sort((a, b) => a.processedText.length - b.processedText.length)
        const newImports = group.map((node) => node.processedText).join('\n')

        // 如果当前导入代码块不等于排序后的导入代码块,则重新排序,进行修复
        if (currentText !== newImports) {
          context.report({
            node: importDeclarations[0],
            message: '导入语句未按照排序规则进行排序',
            fix(fixer) {
              return fixer.replaceTextRange([start, end], newImports)
            }
          })
        }
      }
    }
  }
}

最后

感兴趣的可移步源码

相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95271 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大1 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师1 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学1 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端